--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+import java.nio.channels.*;
+import com.solidosystems.tuplesoup.filter.*;
+
+/**
+ * The table stores a group of rows.
+ * Every row must have a unique id within a table.
+ */
+public class DualFileTable implements Table{
+
+
+ private int INDEXCACHESIZE=8192;
+
+ private String filealock="filea-dummy";
+ private String fileblock="fileb-dummy";
+
+ private DataOutputStream fileastream=null;
+ private DataOutputStream filebstream=null;
+ private RandomAccessFile filearandom=null;
+ private RandomAccessFile filebrandom=null;
+ FileChannel fca=null;
+ FileChannel fcb=null;
+ private TableIndex index=null;
+
+ private long fileaposition=0;
+ private long filebposition=0;
+
+ private boolean rowswitch=true;
+
+ private String title;
+ private String location;
+
+ private TableIndexNode indexcachefirst;
+ private TableIndexNode indexcachelast;
+ private int indexcacheusage;
+ private Hashtable<String,TableIndexNode> indexcache;
+
+ // Statistic counters
+ long stat_add=0;
+ long stat_update=0;
+ long stat_delete=0;
+ long stat_add_size=0;
+ long stat_update_size=0;
+ long stat_read_size=0;
+ long stat_read=0;
+ long stat_cache_hit=0;
+ long stat_cache_miss=0;
+ long stat_cache_drop=0;
+
+ protected String statlock="stat-dummy";
+
+ /**
+ * Return the current values of the statistic counters and reset them.
+ * The current counters are:
+ * <ul>
+ * <li>stat_table_add
+ * <li>stat_table_update
+ * <li>stat_table_delete
+ * <li>stat_table_add_size
+ * <li>stat_table_update_size
+ * <li>stat_table_read_size
+ * <li>stat_table_read
+ * <li>stat_table_cache_hit
+ * <li>stat_table_cache_miss
+ * <li>stat_table_cache_drop
+ * </ul>
+ * Furthermore, the index will be asked to deliver separate index specific counters
+ */
+ public Hashtable<String,Long> readStatistics(){
+ Hashtable<String,Long> hash=new Hashtable<String,Long>();
+ synchronized(statlock){
+ hash.put("stat_table_add",stat_add);
+ hash.put("stat_table_update",stat_update);
+ hash.put("stat_table_delete",stat_delete);
+ hash.put("stat_table_add_size",stat_add_size);
+ hash.put("stat_table_update_size",stat_update_size);
+ hash.put("stat_table_read_size",stat_read_size);
+ hash.put("stat_table_read",stat_read);
+ hash.put("stat_table_cache_hit",stat_cache_hit);
+ hash.put("stat_table_cache_miss",stat_cache_miss);
+ hash.put("stat_table_cache_drop",stat_cache_drop);
+ stat_add=0;
+ stat_update=0;
+ stat_delete=0;
+ stat_add_size=0;
+ stat_update_size=0;
+ stat_read_size=0;
+ stat_read=0;
+ stat_cache_hit=0;
+ stat_cache_miss=0;
+ stat_cache_drop=0;
+ Hashtable<String,Long> ihash=index.readStatistics();
+ hash.putAll(ihash);
+ }
+ return hash;
+ }
+
+ /**
+ * Create a new table object with the default flat index model
+ */
+ public DualFileTable(String title,String location) throws IOException{
+ this.title=title;
+ this.location=location;
+ if(!this.location.endsWith(File.separator))this.location+=File.separator;
+ index=new FlatIndex(getFileName(INDEX));
+ indexcachefirst=null;
+ indexcachelast=null;
+ indexcacheusage=0;
+ indexcache=new Hashtable<String,TableIndexNode>();
+ }
+
+ /**
+ * Create a new table object with a specific index model
+ */
+ public DualFileTable(String title,String location, int indextype) throws IOException{
+ this.title=title;
+ this.location=location;
+ if(!this.location.endsWith(File.separator))this.location+=File.separator;
+ switch(indextype){
+ case PAGED : index=new PagedIndex(getFileName(INDEX));
+ break;
+ case FLAT : index=new FlatIndex(getFileName(INDEX));
+ break;
+ case MEMORY : index=new MemoryIndex(getFileName(INDEX));
+ break;
+ }
+ indexcachefirst=null;
+ indexcachelast=null;
+ indexcacheusage=0;
+ indexcache=new Hashtable<String,TableIndexNode>();
+ }
+
+ /**
+ * Set the maximal allowable size of the index cache.
+ */
+ public void setIndexCacheSize(int newsize){
+ INDEXCACHESIZE=newsize;
+ }
+
+ /**
+ * Close all open file streams
+ */
+ public void close(){
+ try{
+ if(fileastream!=null)fileastream.close();
+ if(filebstream!=null)filebstream.close();
+ if(filearandom!=null)filearandom.close();
+ if(filebrandom!=null)filebrandom.close();
+ index.close();
+ }catch(Exception e){}
+ }
+
+ /**
+ * Returns the name of this table
+ */
+ public String getTitle(){
+ return title;
+ }
+
+ /**
+ * Returns the location of this tables datafiles
+ */
+ public String getLocation(){
+ return location;
+ }
+
+ protected String getFileName(int type){
+ switch(type){
+ case FILEB : return location+title+".a";
+ case FILEA : return location+title+".b";
+ case INDEX : return location+title+".index";
+ }
+ return null;
+ }
+
+ /**
+ * Delete the files created by this table object.
+ * Be aware that this will delete any data stored in this table!
+ */
+ public void deleteFiles(){
+ try{
+ File ftest=new File(getFileName(FILEA));
+ ftest.delete();
+ }catch(Exception e){}
+ try{
+ File ftest=new File(getFileName(FILEB));
+ ftest.delete();
+ }catch(Exception e){}
+ try{
+ File ftest=new File(getFileName(INDEX));
+ ftest.delete();
+ }catch(Exception e){}
+ }
+
+ private synchronized void openFile(int type) throws IOException{
+ switch(type){
+ case FILEA : if(fileastream==null){
+ fileastream=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(getFileName(FILEA),true)));
+ File ftest=new File(getFileName(FILEA));
+ fileaposition=ftest.length();
+ }
+ break;
+ case FILEB : if(filebstream==null){
+ filebstream=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(getFileName(FILEB),true)));
+ File ftest=new File(getFileName(FILEB));
+ filebposition=ftest.length();
+ }
+ break;
+ }
+ }
+
+ /**
+ * Adds a row of data to this table.
+ */
+ public void addRow(Row row) throws IOException{
+ // Distribute new rows between the two datafiles by using the rowswitch, but don't spend time synchronizing... this does not need to be acurate!
+ if(rowswitch){
+ addRowA(row);
+ }else{
+ addRowB(row);
+ }
+ rowswitch=!rowswitch;
+ }
+
+ private void addCacheEntry(TableIndexEntry entry){
+ synchronized(indexcache){
+ if(indexcacheusage>INDEXCACHESIZE){
+ // remove first entry
+ TableIndexNode node=indexcachefirst;
+ indexcache.remove(node.getData().getId());
+ indexcacheusage--;
+ synchronized(statlock){
+ stat_cache_drop++;
+ }
+ indexcachefirst=node.getNext();
+ if(indexcachefirst==null){
+ indexcachelast=null;
+ }else{
+ indexcachefirst.setPrevious(null);
+ }
+ }
+ TableIndexNode node=new TableIndexNode(indexcachelast,entry);
+ if(indexcachelast!=null){
+ indexcachelast.setNext(node);
+ }
+ if(indexcachefirst==null){
+ indexcachefirst=node;
+ }
+ indexcachelast=node;
+ indexcache.put(entry.getId(),node);
+ indexcacheusage++;
+ }
+ }
+
+ private void addRowA(Row row) throws IOException{
+ synchronized(filealock){
+ openFile(FILEA);
+ int pre=fileastream.size();
+ row.writeToStream(fileastream);
+ int post=fileastream.size();
+ fileastream.flush();
+ synchronized(statlock){
+ stat_add++;
+ stat_add_size+=row.getSize();
+ }
+ index.addEntry(row.getId(),row.getSize(),FILEA,fileaposition);
+ if(INDEXCACHESIZE>0){
+ TableIndexEntry entry=new TableIndexEntry(row.getId(),row.getSize(),FILEA,fileaposition);
+ addCacheEntry(entry);
+ }
+ fileaposition+=Row.calcSize(pre,post);
+ }
+ }
+ private void addRowB(Row row) throws IOException{
+ synchronized(fileblock){
+ openFile(FILEB);
+ int pre=filebstream.size();
+ row.writeToStream(filebstream);
+ int post=filebstream.size();
+ filebstream.flush();
+ synchronized(statlock){
+ stat_add++;
+ stat_add_size+=row.getSize();
+ }
+ index.addEntry(row.getId(),row.getSize(),FILEB,filebposition);
+ if(INDEXCACHESIZE>0){
+ TableIndexEntry entry=new TableIndexEntry(row.getId(),row.getSize(),FILEB,filebposition);
+ addCacheEntry(entry);
+ }
+ filebposition+=Row.calcSize(pre,post);
+ }
+ }
+
+
+ private void updateCacheEntry(TableIndexEntry entry){
+ synchronized(indexcache){
+ if(indexcache.containsKey(entry.getId())){
+ TableIndexNode node=indexcache.get(entry.getId());
+ node.setData(entry);
+ if(node!=indexcachelast){
+ if(node==indexcachefirst){
+ indexcachefirst=node.getNext();
+ }
+ node.remove();
+ indexcachelast.setNext(node);
+ node.setPrevious(indexcachelast);
+ node.setNext(null);
+ indexcachelast=node;
+ }
+ }else{
+ addCacheEntry(entry);
+ }
+ }
+ }
+
+ private void removeCacheEntry(String id){
+ synchronized(indexcache){
+ if(indexcache.containsKey(id)){
+ TableIndexNode node=indexcache.get(id);
+ indexcache.remove(id);
+ if(indexcacheusage==1){
+ indexcachefirst=null;
+ indexcachelast=null;
+ indexcacheusage=0;
+ return;
+ }
+ if(node==indexcachefirst){
+ indexcachefirst=node.getNext();
+ indexcachefirst.setPrevious(null);
+ }else if(node==indexcachelast){
+ indexcachelast=node.getPrevious();
+ indexcachelast.setNext(null);
+ }else{
+ node.remove();
+ }
+ indexcacheusage--;
+ synchronized(statlock){
+ stat_cache_drop++;
+ }
+ }
+ }
+ }
+
+ private TableIndexEntry getCacheEntry(String id){
+ synchronized(indexcache){
+ if(indexcache.containsKey(id)){
+ TableIndexNode node=indexcache.get(id);
+ if(node!=indexcachelast){
+ if(node==indexcachefirst){
+ indexcachefirst=node.getNext();
+ }
+ node.remove();
+ indexcachelast.setNext(node);
+ node.setPrevious(indexcachelast);
+ node.setNext(null);
+ indexcachelast=node;
+ }
+ synchronized(statlock){
+ stat_cache_hit++;
+ }
+ return node.getData();
+ }
+ }
+ synchronized(statlock){
+ stat_cache_miss++;
+ }
+ return null;
+ }
+
+ /**
+ * Adds a row to this table if it doesn't already exist, if it does it updates the row instead.
+ * This method is much slower than directly using add or update, so only use it if you don't know wether or not the row already exists.
+ */
+ public void addOrUpdateRow(Row row) throws IOException{
+ Row tmprow=getRow(row.getId());
+ if(tmprow==null){
+ addRow(row);
+ }else{
+ updateRow(row);
+ }
+ }
+
+ /**
+ * Updates a row stored in this table.
+ */
+ public void updateRow(Row row) throws IOException{
+ TableIndexEntry entry=null;
+ // Handle index entry caching
+ if(INDEXCACHESIZE>0){
+ synchronized(indexcache){
+ entry=getCacheEntry(row.getId());
+ if(entry==null){
+ entry=index.scanIndex(row.getId());
+ addCacheEntry(entry);
+ }
+ }
+ }else{
+ entry=index.scanIndex(row.getId());
+ }
+ if(entry.getRowSize()>=row.getSize()){
+ // Add to the existing location
+ switch(entry.getLocation()){
+ case FILEA :synchronized(filealock){
+ if(filearandom==null){
+ filearandom=new RandomAccessFile(getFileName(FILEA),"rw");
+ fca=filearandom.getChannel();
+ }
+ filearandom.seek(entry.getPosition());
+ row.writeToFile(filearandom);
+
+ fca.force(false);
+ }
+ break;
+ case FILEB :synchronized(fileblock){
+ if(filebrandom==null){
+ filebrandom=new RandomAccessFile(getFileName(FILEB),"rw");
+ fcb=filebrandom.getChannel();
+ }
+ filebrandom.seek(entry.getPosition());
+ row.writeToFile(filebrandom);
+
+ fcb.force(false);
+ }
+ break;
+ }
+ }else{
+ if(rowswitch){
+ updateRowA(row);
+ }else{
+ updateRowB(row);
+ }
+ rowswitch=!rowswitch;
+ }
+ synchronized(statlock){
+ stat_update++;
+ stat_update_size+=row.getSize();
+ }
+ }
+
+ private void updateRowA(Row row) throws IOException{
+ synchronized(filealock){
+ openFile(FILEA);
+ int pre=fileastream.size();
+ row.writeToStream(fileastream);
+ int post=fileastream.size();
+ fileastream.flush();
+ index.updateEntry(row.getId(),row.getSize(),FILEA,fileaposition);
+
+ // Handle index entry caching
+ if(INDEXCACHESIZE>0){
+ updateCacheEntry(new TableIndexEntry(row.getId(),row.getSize(),FILEA,fileaposition));
+ }
+ fileaposition+=Row.calcSize(pre,post);
+ }
+ }
+
+ private void updateRowB(Row row) throws IOException{
+ synchronized(fileblock){
+ openFile(FILEB);
+ int pre=filebstream.size();
+ row.writeToStream(filebstream);
+ int post=filebstream.size();
+ filebstream.flush();
+ index.updateEntry(row.getId(),row.getSize(),FILEB,filebposition);
+ // Handle index entry caching
+ // Handle index entry caching
+ if(INDEXCACHESIZE>0){
+ updateCacheEntry(new TableIndexEntry(row.getId(),row.getSize(),FILEB,filebposition));
+ }
+ filebposition+=Row.calcSize(pre,post);
+ }
+ }
+
+ /**
+ * Marks a row as deleted in the index.
+ * Be aware that the space consumed by the row is not actually reclaimed.
+ */
+ public void deleteRow(Row row) throws IOException{
+ // Handle index entry caching
+ if(INDEXCACHESIZE>0){
+ removeCacheEntry(row.getId());
+ }
+ index.updateEntry(row.getId(),row.getSize(),DELETE,0);
+ synchronized(statlock){
+ stat_delete++;
+ }
+ }
+
+ /**
+ * Returns a tuplestream containing the given list of rows
+ */
+ public TupleStream getRows(List<String> rows) throws IOException{
+ return new IndexedTableReader(this,index.scanIndex(rows));
+ }
+
+ /**
+ * Returns a tuplestream containing the rows matching the given rowmatcher
+ */
+ public TupleStream getRows(RowMatcher matcher) throws IOException{
+ return new IndexedTableReader(this,index.scanIndex(),matcher);
+ }
+
+ /**
+ * Returns a tuplestream containing those rows in the given list that matches the given RowMatcher
+ */
+ public TupleStream getRows(List<String> rows,RowMatcher matcher) throws IOException{
+ return new IndexedTableReader(this,index.scanIndex(rows),matcher);
+ }
+
+ /**
+ * Returns a tuplestream of all rows in this table.
+ */
+ public TupleStream getRows() throws IOException{
+ // return new TableReader(this);
+ return new IndexedTableReader(this,index.scanIndex());
+ }
+
+ /**
+ * Returns a single row stored in this table.
+ * If the row does not exist in the table, null will be returned.
+ */
+ public Row getRow(String id) throws IOException{
+ TableIndexEntry entry=null;
+ // Handle index entry caching
+ if(INDEXCACHESIZE>0){
+ synchronized(indexcache){
+ entry=getCacheEntry(id);
+ if(entry==null){
+ entry=index.scanIndex(id);
+ if(entry!=null){
+ addCacheEntry(entry);
+ }
+ }
+ }
+ }else{
+ entry=index.scanIndex(id);
+ }
+ if(entry!=null){
+ long dataoffset=0;
+ DataInputStream data=null;
+ if(entry.location==Table.FILEA){
+ data=new DataInputStream(new BufferedInputStream(new FileInputStream(getFileName(Table.FILEA))));
+ }else if(entry.location==Table.FILEB){
+ data=new DataInputStream(new BufferedInputStream(new FileInputStream(getFileName(Table.FILEB))));
+ }
+ if(data!=null){
+ while(dataoffset!=entry.position){
+ dataoffset+=data.skipBytes((int)(entry.position-dataoffset));
+ }
+ Row row=Row.readFromStream(data);
+ data.close();
+ synchronized(statlock){
+ stat_read++;
+ stat_read_size+=row.getSize();
+ }
+ return row;
+ }
+
+ }
+ return null;
+ }
+ }
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.util.*;
+import java.io.*;
+import java.nio.channels.*;
+
+public class FlatIndex implements TableIndex{
+ private DataOutputStream out=null;
+ private String filename;
+
+ private long stat_read=0;
+ private long stat_write=0;
+ private long stat_scan=0;
+
+ public FlatIndex(String filename) throws IOException{
+ this.filename=filename;
+ File ftest=new File(filename);
+ if(!ftest.exists())ftest.createNewFile();
+ }
+
+ public Hashtable<String,Long> readStatistics(){
+ Hashtable<String,Long> hash=new Hashtable<String,Long>();
+ hash.put("stat_index_read",stat_read);
+ hash.put("stat_index_write",stat_write);
+ hash.put("stat_index_scan",stat_scan);
+ stat_read=0;
+ stat_write=0;
+ stat_scan=0;
+ return hash;
+ }
+
+ public void close(){
+ try{
+ out.close();
+ }catch(Exception e){}
+ }
+
+ public List<TableIndexEntry> scanIndex() throws IOException{
+ ArrayList<TableIndexEntry> lst=new ArrayList<TableIndexEntry>();
+ DataInputStream data=new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
+ try{
+ while(true){
+ TableIndexEntry entry=TableIndexEntry.readData(data);
+ stat_read++;
+ if(entry!=null){
+ if(entry.getLocation()!=Table.DELETE){
+ lst.add(entry);
+ }
+ }
+ }
+ }catch(EOFException eofe){
+ }
+ return lst;
+ }
+
+ private long getOffset(String id) throws IOException{
+ DataInputStream in=new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
+ long offset=TableIndexEntry.scanForOffset(id,in);
+ stat_scan++;
+ in.close();
+ return offset;
+ }
+
+ public synchronized void updateEntry(String id,int rowsize,int location,long position) throws IOException{
+ if(out!=null){
+ out.close();
+ out=null;
+ }
+ long offset=getOffset(id);
+ RandomAccessFile data=new RandomAccessFile(filename,"rw");
+ data.seek(offset);
+ TableIndexEntry entry=new TableIndexEntry(id,rowsize,location,position);
+ entry.writeData(data);
+ stat_write++;
+ FileChannel fc=data.getChannel();
+ fc.force(false);
+ data.close();
+ }
+
+ public synchronized void addEntry(String id,int rowsize,int location,long position) throws IOException{
+ if(out==null)out=new DataOutputStream(new FileOutputStream(filename,true));
+ TableIndexEntry entry=new TableIndexEntry(id,rowsize,location,position);
+ entry.writeData(out);
+ stat_write++;
+ out.flush();
+ }
+
+ public TableIndexEntry scanIndex(String id) throws IOException{
+ DataInputStream data=new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
+ while(true){
+ try{
+ TableIndexEntry entry=TableIndexEntry.lookForData(id,data);
+ stat_read++;
+ if(entry!=null){
+ data.close();
+ return entry;
+ }
+ }catch(EOFException eofe){
+ data.close();
+ return null;
+ }
+ }
+ }
+
+ public List<TableIndexEntry> scanIndex(List<String> rows) throws IOException{
+ HashSet<String>rowhash=new HashSet<String>();
+ for(int i=0;i<rows.size();i++){
+ rowhash.add(rows.get(i));
+ }
+ Hashtable<String,TableIndexEntry> entries=new Hashtable<String,TableIndexEntry>();
+ DataInputStream data=new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
+ try{
+ while(true){
+ TableIndexEntry entry=TableIndexEntry.readData(data);
+ stat_read++;
+ if(entry!=null){
+ if(rowhash.contains(entry.getId())){
+ if(entry.getLocation()!=Table.DELETE){
+ entries.put(entry.getId(),entry);
+ }
+ }
+ }
+ }
+ }catch(EOFException eofe){
+ }
+ List<TableIndexEntry> result=new ArrayList<TableIndexEntry>();
+ Iterator<String>it=rows.iterator();
+ while(it.hasNext()){
+ String id=it.next();
+ if(entries.containsKey(id)){
+ result.add(entries.get(id));
+ }
+ }
+ return result;
+ }
+}
\ No newline at end of file
--- /dev/null
+
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+import java.nio.channels.*;
+import com.solidosystems.tuplesoup.filter.*;
+
+/**
+ * The table stores a group of rows.
+ * Every row must have a unique id within a table.
+ */
+public class HashedTable implements Table{
+ private int TABLESETSIZE=16;
+ private List<Table> tableset;
+ private String title;
+ private String location;
+
+ /**
+ * Create a new table object with the default flat index model
+ */
+ public HashedTable(String title,String location) throws IOException{
+ this.title=title;
+ this.location=location;
+ tableset=new ArrayList<Table>();
+ for(int i=0;i<TABLESETSIZE;i++){
+ tableset.add(new DualFileTable(title+"_"+i,location));
+ }
+ }
+
+ /**
+ * Create a new table object with a specific index model
+ */
+ public HashedTable(String title,String location, int indextype) throws IOException{
+ this.title=title;
+ this.location=location;
+ tableset=new ArrayList<Table>();
+ for(int i=0;i<TABLESETSIZE;i++){
+ tableset.add(new DualFileTable(title+"_"+i,location,indextype));
+ }
+ }
+
+
+ public Hashtable<String,Long> readStatistics(){
+ Hashtable<String,Long> results=new Hashtable<String,Long>();
+ for(int i=0;i<TABLESETSIZE;i++){
+ Hashtable<String,Long> tmp=tableset.get(i).readStatistics();
+ Set<String> keys=tmp.keySet();
+ Iterator<String> it=keys.iterator();
+ while(it.hasNext()){
+ String key=it.next();
+ long value=tmp.get(key);
+ if(results.containsKey(key)){
+ results.put(key,results.get(key)+value);
+ }else{
+ results.put(key,value);
+ }
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Returns the name of this table
+ */
+ public String getTitle(){
+ return title;
+ }
+
+ /**
+ * Returns the location of this tables datafiles
+ */
+ public String getLocation(){
+ return location;
+ }
+
+ /**
+ * Delete the files created by this table object.
+ * Be aware that this will delete any data stored in this table!
+ */
+ public void deleteFiles(){
+ for(int i=0;i<TABLESETSIZE;i++){
+ tableset.get(i).deleteFiles();
+ }
+ }
+
+ public void close(){
+ for(int i=0;i<TABLESETSIZE;i++){
+ tableset.get(i).close();
+ }
+ }
+
+ public void setIndexCacheSize(int size){
+ for(int i=0;i<TABLESETSIZE;i++){
+ tableset.get(i).setIndexCacheSize(size/TABLESETSIZE);
+ }
+ }
+
+ private Table getTableForId(String id){
+ return tableset.get(id.hashCode() & (TABLESETSIZE-1));
+ }
+
+ /**
+ * Returns a single row stored in this table.
+ * If the row does not exist in the table, null will be returned.
+ */
+ public Row getRow(String id) throws IOException{
+ Table tbl=getTableForId(id);
+ return tbl.getRow(id);
+ }
+
+ /**
+ * Returns a tuplestream of all rows in this table.
+ */
+ public TupleStream getRows() throws IOException{
+ TupleStreamMerger merge=new TupleStreamMerger();
+ for(int i=0;i<TABLESETSIZE;i++){
+ merge.addStream(tableset.get(i).getRows());
+ }
+ return merge;
+ }
+ /**
+ * Returns a tuplestream containing the given list of rows
+ */
+ public TupleStream getRows(List<String> rows) throws IOException{
+ List<List<String>> listset=new ArrayList<List<String>>();
+ for(int i=0;i<TABLESETSIZE;i++){
+ listset.add(new ArrayList<String>());
+ }
+ for(int i=0;i<rows.size();i++){
+ String id=rows.get(i);
+ listset.get(id.hashCode() & TABLESETSIZE).add(id);
+ }
+ TupleStreamMerger merge=new TupleStreamMerger();
+ for(int i=0;i<TABLESETSIZE;i++){
+ if(listset.get(i).size()>0){
+ merge.addStream(tableset.get(i).getRows(listset.get(i)));
+ }
+ }
+ return merge;
+ }
+
+ /**
+ * Returns a tuplestream containing the rows matching the given rowmatcher
+ */
+ public TupleStream getRows(RowMatcher matcher) throws IOException{
+ TupleStreamMerger merge=new TupleStreamMerger();
+ for(int i=0;i<TABLESETSIZE;i++){
+ merge.addStream(tableset.get(i).getRows(matcher));
+ }
+ return merge;
+ }
+
+ /**
+ * Returns a tuplestream containing those rows in the given list that matches the given RowMatcher
+ */
+ public TupleStream getRows(List<String> rows,RowMatcher matcher) throws IOException{
+ List<List<String>> listset=new ArrayList<List<String>>();
+ for(int i=0;i<TABLESETSIZE;i++){
+ listset.add(new ArrayList<String>());
+ }
+ for(int i=0;i<rows.size();i++){
+ String id=rows.get(i);
+ listset.get(id.hashCode() & TABLESETSIZE).add(id);
+ }
+ TupleStreamMerger merge=new TupleStreamMerger();
+ for(int i=0;i<TABLESETSIZE;i++){
+ if(listset.get(i).size()>0){
+ merge.addStream(tableset.get(i).getRows(listset.get(i),matcher));
+ }
+ }
+ return merge;
+ }
+
+ /**
+ * Marks a row as deleted in the index.
+ * Be aware that the space consumed by the row is not actually reclaimed.
+ */
+ public void deleteRow(Row row) throws IOException{
+ getTableForId(row.getId()).deleteRow(row);
+ }
+
+ /**
+ * Adds a row of data to this table.
+ */
+ public void addRow(Row row) throws IOException{
+ getTableForId(row.getId()).addRow(row);
+ }
+
+ /**
+ * Adds a row to this table if it doesn't already exist, if it does it updates the row instead.
+ * This method is much slower than directly using add or update, so only use it if you don't know wether or not the row already exists.
+ */
+ public void addOrUpdateRow(Row row) throws IOException{
+ getTableForId(row.getId()).addOrUpdateRow(row);
+ }
+
+ /**
+ * Updates a row stored in this table.
+ */
+ public void updateRow(Row row) throws IOException{
+ getTableForId(row.getId()).updateRow(row);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ package com.solidosystems.tuplesoup.core;
+
+ import com.solidosystems.tuplesoup.filter.*;
+ import java.io.*;
+ import java.util.*;
+
+public class IndexedTableReader extends TupleStream{
+ private DataInputStream fileastream=null;
+ private DataInputStream filebstream=null;
+ private long fileaposition=0;
+ private long filebposition=0;
+
+ private List<TableIndexEntry>fileaentries;
+ private List<TableIndexEntry>filebentries;
+
+ private List<TableIndexEntry>entries;
+
+ private Hashtable<String,Row>fileabuffer;
+ private Hashtable<String,Row>filebbuffer;
+
+ private List<String>rows;
+ private int rowpointer;
+ private Row next=null;
+
+ private DualFileTable table;
+
+ private RowMatcher matcher=null;
+
+ public IndexedTableReader(DualFileTable table,List<TableIndexEntry>entries) throws IOException{
+ this.table=table;
+ this.rows=rows;
+ rowpointer=0;
+
+ this.entries=entries;
+ fileaentries=new ArrayList<TableIndexEntry>();
+ filebentries=new ArrayList<TableIndexEntry>();
+
+ Iterator<TableIndexEntry> it=entries.iterator();
+ while(it.hasNext()){
+ TableIndexEntry entry=it.next();
+ // TODO: we really shouldn't get nulls here
+ if(entry!=null){
+ if(entry.location==Table.FILEA){
+ fileaentries.add(entry);
+ }else if(entry.location==Table.FILEB){
+ filebentries.add(entry);
+ }
+ }
+ }
+
+ Collections.sort(fileaentries);
+ Collections.sort(filebentries);
+
+ fileabuffer=new Hashtable<String,Row>();
+ filebbuffer=new Hashtable<String,Row>();
+
+ readNext();
+ }
+
+
+ public IndexedTableReader(DualFileTable table,List<TableIndexEntry>entries,RowMatcher matcher) throws IOException{
+ this.table=table;
+ this.rows=rows;
+ rowpointer=0;
+ this.matcher=matcher;
+
+ this.entries=entries;
+ fileaentries=new ArrayList<TableIndexEntry>();
+ filebentries=new ArrayList<TableIndexEntry>();
+
+ Iterator<TableIndexEntry> it=entries.iterator();
+ while(it.hasNext()){
+ TableIndexEntry entry=it.next();
+ // TODO: we really shouldn't get nulls here
+ if(entry!=null){
+ if(entry.location==Table.FILEA){
+ fileaentries.add(entry);
+ }else if(entry.location==Table.FILEB){
+ filebentries.add(entry);
+ }
+ }
+ }
+
+ Collections.sort(fileaentries);
+ Collections.sort(filebentries);
+
+ fileabuffer=new Hashtable<String,Row>();
+ filebbuffer=new Hashtable<String,Row>();
+
+ readNext();
+ }
+
+ private void readNextFromFileA(TableIndexEntry entry) throws IOException{
+ if(fileabuffer.containsKey(entry.id)){
+ next=fileabuffer.remove(entry.id);
+ return;
+ }
+ while(true){
+ if(fileaentries.size()>0){
+ TableIndexEntry nextfilea=fileaentries.remove(0);
+ if(fileastream==null){
+ fileastream=new DataInputStream(new BufferedInputStream(new FileInputStream(table.getFileName(Table.FILEA))));
+ fileaposition=0;
+ }
+ if(fileaposition>nextfilea.position){
+ // We have already read this entry... skip it
+ // readNextFromFileA(entry);
+ // return;
+ }else{
+ while(fileaposition!=nextfilea.position){
+ fileaposition+=fileastream.skipBytes((int)(nextfilea.position-fileaposition));
+ }
+ Row row=Row.readFromStream(fileastream);
+ synchronized(table.statlock){
+ table.stat_read_size+=row.getSize();
+ table.stat_read++;
+ }
+ fileaposition+=row.getSize();
+ if(row.getId().equals(entry.id)){
+ next=row;
+ return;
+ }else{
+ fileabuffer.put(row.getId(),row);
+ // readNextFromFileA(entry);
+ }
+ }
+ }else{
+ next=null;
+ return;
+ }
+ }
+ }
+
+ private void readNextFromFileB(TableIndexEntry entry) throws IOException{
+ if(filebbuffer.containsKey(entry.id)){
+ next=filebbuffer.remove(entry.id);
+ return;
+ }
+ while(true){
+ if(filebentries.size()>0){
+ TableIndexEntry nextfileb=filebentries.remove(0);
+ if(filebstream==null){
+ filebstream=new DataInputStream(new BufferedInputStream(new FileInputStream(table.getFileName(Table.FILEB))));
+ filebposition=0;
+ }
+ if(filebposition>nextfileb.position){
+ // We have already read this entry... skip it
+ // readNextFromFileB(entry);
+ // return;
+ }else{
+ while(filebposition!=nextfileb.position){
+ filebposition+=filebstream.skipBytes((int)(nextfileb.position-filebposition));
+ }
+ Row row=Row.readFromStream(filebstream);
+ synchronized(table.statlock){
+ table.stat_read_size+=row.getSize();
+ table.stat_read++;
+ }
+ filebposition+=row.getSize();
+ if(row.getId().equals(entry.id)){
+ next=row;
+ return;
+ }else{
+ filebbuffer.put(row.getId(),row);
+ // readNextFromFileB(entry);
+ }
+ }
+ }else{
+ next=null;
+ return;
+ }
+ }
+ }
+
+ private void readNext() throws IOException{
+ if(entries.size()>rowpointer){
+ TableIndexEntry entry=entries.get(rowpointer++);
+ if(entry!=null){
+ switch(entry.location){
+ case Table.FILEA : readNextFromFileA(entry);
+ // return;
+ break;
+ case Table.FILEB : readNextFromFileB(entry);
+ // return;
+ break;
+ }
+ if(next!=null){
+ if(matcher!=null){
+ if(!matcher.matches(next)){
+ readNext();
+ }
+ }
+ }
+ return;
+ }else{
+ readNext();
+ return;
+ }
+ }
+ try{
+ if(fileastream!=null)fileastream.close();
+ }catch(Exception e){}
+ try{
+ if(filebstream!=null)filebstream.close();
+ }catch(Exception e){}
+ next=null;
+ }
+
+ public boolean hasNext(){
+ if(next!=null)return true;
+ return false;
+ }
+
+ public Row next(){
+ try{
+ if(next!=null){
+ Row tmp=next;
+ readNext();
+ return tmp;
+ }
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public void remove(){
+
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.util.*;
+import java.io.*;
+
+public class MemoryIndex implements TableIndex{
+ private DataOutputStream out=null;
+ private String filename;
+ private Hashtable<String,TableIndexEntry> cache;
+
+ private long stat_write=0;
+
+ public MemoryIndex(String filename) throws IOException{
+ this.filename=filename;
+ File ftest=new File(filename);
+ if(!ftest.exists())ftest.createNewFile();
+ cache=new Hashtable<String,TableIndexEntry>();
+ DataInputStream in=new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
+ try{
+ while(true){
+ TableIndexEntry entry=TableIndexEntry.readData(in);
+ if(entry.getLocation()==Table.DELETE){
+ cache.remove(entry.getId());
+ }else{
+ cache.put(entry.getId(),entry);
+ }
+ }
+ }catch(EOFException e){}
+ out=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(filename,true)));
+ }
+
+ public Hashtable<String,Long> readStatistics(){
+ Hashtable<String,Long> hash=new Hashtable<String,Long>();
+ hash.put("stat_index_write",stat_write);
+ stat_write=0;
+ return hash;
+ }
+
+ public void close(){
+ try{
+ out.close();
+ }catch(Exception e){}
+ }
+
+ public synchronized List<TableIndexEntry> scanIndex() throws IOException{
+ ArrayList<TableIndexEntry> lst=new ArrayList<TableIndexEntry>();
+ Iterator<TableIndexEntry> it=cache.values().iterator();
+ while(it.hasNext()){
+ TableIndexEntry entry=it.next();
+ if(entry.getLocation()!=Table.DELETE)lst.add(entry);
+ }
+ return lst;
+ }
+
+ public synchronized void updateEntry(String id,int rowsize,int location,long position) throws IOException{
+ TableIndexEntry entry=new TableIndexEntry(id,rowsize,location,position);
+ entry.writeData(out);
+ out.flush();
+ stat_write++;
+ cache.put(entry.getId(),entry);
+ }
+
+ public synchronized void addEntry(String id,int rowsize,int location,long position) throws IOException{
+ TableIndexEntry entry=new TableIndexEntry(id,rowsize,location,position);
+ entry.writeData(out);
+ out.flush();
+ stat_write++;
+ cache.put(entry.getId(),entry);
+ }
+
+ public synchronized TableIndexEntry scanIndex(String id) throws IOException{
+ if(!cache.containsKey(id))return null;
+ return cache.get(id);
+ }
+
+ public synchronized List<TableIndexEntry> scanIndex(List<String> rows) throws IOException{
+ List<TableIndexEntry> result=new ArrayList<TableIndexEntry>();
+ for(int i=0;i<rows.size();i++){
+ if(cache.containsKey(rows.get(i))){
+ TableIndexEntry entry=cache.get(rows.get(i));
+ if(entry!=null)result.add(entry);
+ }
+ }
+ return result;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+import java.nio.channels.*;
+
+public class PagedIndex implements TableIndex{
+ protected static final int INITIALPAGEHASH=1024;
+ protected static final int PAGESIZE=2048;
+
+ private RandomAccessFile out=null;
+ private String filename;
+ private TableIndexPage[] root=null;
+
+ private long stat_read=0;
+ private long stat_write=0;
+ protected long stat_create_page=0;
+ protected long stat_page_next=0;
+ protected long stat_page_branch=0;
+
+ public PagedIndex(String filename) throws IOException{
+ this.filename=filename;
+ File ftest=new File(filename);
+ if(!ftest.exists())ftest.createNewFile();
+ out=new RandomAccessFile(filename,"rw");
+ root=new TableIndexPage[INITIALPAGEHASH];
+ if(out.length()>0){
+ for(int i=0;i<INITIALPAGEHASH;i++){
+ root[i]=new TableIndexPage(this,out);
+ root[i].setFirst();
+ out.seek(root[i].getEndLocation());
+ }
+ }else{
+ for(int i=0;i<INITIALPAGEHASH;i++){
+ root[i]=TableIndexPage.createNewPage(this,out,PAGESIZE);
+ root[i].setFirst();
+ }
+ }
+ }
+
+ public Hashtable<String,Long> readStatistics(){
+ Hashtable<String,Long> hash=new Hashtable<String,Long>();
+ hash.put("stat_index_read",stat_read);
+ hash.put("stat_index_write",stat_write);
+ hash.put("stat_index_create_page",stat_create_page);
+ hash.put("stat_index_page_next",stat_page_next);
+ hash.put("stat_index_page_branch",stat_page_branch);
+ stat_read=0;
+ stat_write=0;
+ stat_create_page=0;
+ stat_page_next=0;
+ stat_page_branch=0;
+ return hash;
+ }
+
+ private int rootHash(String id){
+ return id.hashCode() & (INITIALPAGEHASH-1);
+ }
+
+ private synchronized TableIndexPage getFirstFreePage(String id) throws IOException{
+ return root[rootHash(id)].getFirstFreePage(id,id.hashCode());
+ }
+
+ private synchronized long getOffset(String id) throws IOException{
+ if(root==null)return -1;
+ return root[rootHash(id)].getOffset(id,id.hashCode());
+ }
+
+ public synchronized void updateEntry(String id,int rowsize,int location,long position) throws IOException{
+ long offset=getOffset(id);
+ out.seek(offset);
+ TableIndexEntry entry=new TableIndexEntry(id,rowsize,location,position);
+ entry.updateData(out);
+ stat_write++;
+ }
+ public synchronized void addEntry(String id,int rowsize,int location,long position) throws IOException{
+ TableIndexPage page=getFirstFreePage(id);
+ page.addEntry(id,rowsize,location,position);
+ stat_write++;
+ }
+ public synchronized TableIndexEntry scanIndex(String id) throws IOException{
+ if(root==null)return null;
+ return root[rootHash(id)].scanIndex(id,id.hashCode());
+ }
+ public synchronized List<TableIndexEntry> scanIndex(List<String> rows) throws IOException{
+ List<TableIndexEntry> lst=new ArrayList<TableIndexEntry>();
+ for(int i=0;i<rows.size();i++){
+ String id=rows.get(i);
+ TableIndexEntry entry=scanIndex(id);
+ if(entry!=null){
+ if(entry.getLocation()!=Table.DELETE)lst.add(entry);
+ }
+ }
+ return lst;
+ }
+ public synchronized List<TableIndexEntry> scanIndex() throws IOException{
+ ArrayList<TableIndexEntry> lst=new ArrayList<TableIndexEntry>();
+ for(int i=0;i<INITIALPAGEHASH;i++){
+ root[i].addEntriesToList(lst);
+ }
+ return lst;
+ }
+ public void close(){
+ try{
+ if(out!=null){
+ out.close();
+ }
+ }catch(Exception e){}
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+import java.nio.channels.*;
+
+/**
+ * Holds a row of data
+ */
+public class Row{
+ private String id;
+ private int size;
+ private Hashtable<String,Value> values;
+
+ /**
+ * Creates a new empty row with the given row id.
+ */
+ public Row(String id){
+ this.id=id;
+ size=-1;
+ values=new Hashtable<String,Value>();
+ }
+
+ /**
+ * Returns the number of keys in this row.
+ */
+ public int getKeyCount(){
+ return values.size();
+ }
+
+ public Set<String> keySet(){
+ return values.keySet();
+ }
+
+ /**
+ * Returns the actual size in bytes this row will take when written to a stream.
+ */
+ public int getSize(){
+ if(size==-1)recalcSize();
+ return size;
+ }
+
+ /**
+ * Returns a hashcode for this row. This hashcode will be based purely on the id of the row.
+ */
+ public int hashCode(){
+ return id.hashCode();
+ }
+
+ public boolean equals(Object obj){
+ try{
+ Row r=(Row)obj;
+ return r.id.equals(id);
+ }catch(Exception e){}
+ return false;
+ }
+
+ /**
+ * Returns the id of this row.
+ */
+ public String getId(){
+ return id;
+ }
+
+ /**
+ * Stores the given value for the given key.
+ */
+ public void put(String key,Value value){
+ size=-1;
+ values.put(key,value);
+ }
+
+ /**
+ * Stores the given string wrapped in a value object for the given key.
+ */
+ public void put(String key,String value){
+ size=-1;
+ values.put(key,new Value(value));
+ }
+
+ /**
+ * Stores the given int wrapped in a value object for the given key.
+ */
+ public void put(String key,int value){
+ size=-1;
+ values.put(key,new Value(value));
+ }
+
+ /**
+ * Stores the given long wrapped in a value object for the given key.
+ */
+ public void put(String key,long value){
+ size=-1;
+ values.put(key,new Value(value));
+ }
+
+ /**
+ * Stores the given float wrapped in a value object for the given key.
+ */
+ public void put(String key,float value){
+ size=-1;
+ values.put(key,new Value(value));
+ }
+
+ /**
+ * Stores the given double wrapped in a value object for the given key.
+ */
+ public void put(String key,double value){
+ size=-1;
+ values.put(key,new Value(value));
+ }
+
+ /**
+ * Stores the given boolean wrapped in a value object for the given key.
+ */
+ public void put(String key,boolean value){
+ size=-1;
+ values.put(key,new Value(value));
+ }
+
+ /**
+ * Stores the given Date wrapped in a value object for the given key.
+ */
+ public void put(String key,Date value){
+ size=-1;
+ values.put(key,new Value(value));
+ }
+
+ /**
+ * Returns the value stored for the current key, or a null value (not null) if the key does not exist.
+ */
+ public Value get(String key){
+ if(!values.containsKey(key))return new Value();
+ return values.get(key);
+ }
+
+ /**
+ * Returns a string representation of the value stored for the current key.
+ * If the key does not exist, an empty string will be returned.
+ * See the documentation for Value to learn how the string value is generated.
+ */
+ public String getString(String key){
+ if(!values.containsKey(key))return "";
+ return values.get(key).getString();
+ }
+
+ /**
+ * Returns an int representation of the value stored for the current key.
+ * If the key does not exist, 0 will be returned.
+ * See the documentation for Value to learn how the string value is generated.
+ */
+ public int getInt(String key){
+ if(!values.containsKey(key))return 0;
+ return values.get(key).getInt();
+ }
+
+ /**
+ * Returns a long representation of the value stored for the current key.
+ * If the key does not exist, 0 will be returned.
+ * See the documentation for Value to learn how the string value is generated.
+ */
+ public long getLong(String key){
+ if(!values.containsKey(key))return 0;
+ return values.get(key).getLong();
+ }
+
+ /**
+ * Returns a float representation of the value stored for the current key.
+ * If the key does not exist, 0 will be returned.
+ * See the documentation for Value to learn how the string value is generated.
+ */
+ public float getFloat(String key){
+ if(!values.containsKey(key))return 0f;
+ return values.get(key).getFloat();
+ }
+
+ /**
+ * Returns a double representation of the value stored for the current key.
+ * If the key does not exist, 0 will be returned.
+ * See the documentation for Value to learn how the string value is generated.
+ */
+ public double getDouble(String key){
+ if(!values.containsKey(key))return 0d;
+ return values.get(key).getDouble();
+ }
+
+ /**
+ * Returns a boolean representation of the value stored for the current key.
+ * If the key does not exist, false will be returned.
+ * See the documentation for Value to learn how the string value is generated.
+ */
+ public boolean getBoolean(String key){
+ if(!values.containsKey(key))return false;
+ return values.get(key).getBoolean();
+ }
+
+ /**
+ * Returns a Date representation of the value stored for the current key.
+ * If the key does not exist, the date initialized with 0 will be returned.
+ * See the documentation for Value to learn how the string value is generated.
+ */
+ public Date getTimestamp(String key){
+ if(!values.containsKey(key))return new Date(0);
+ return values.get(key).getTimestamp();
+ }
+
+ /**
+ * Utility function to calculate the distance between ints, allowing for a single wraparound.
+ */
+ protected static int calcSize(int pre,int post){
+ if(post>pre)return post-pre;
+ return (Integer.MAX_VALUE-pre)+post;
+ }
+
+ /**
+ * Recalculate the size of the row. Be aware that this method will actually write the full row to a buffer to calculate the size.
+ * Its a slow and memory consuming method to call!
+ */
+ private void recalcSize(){
+ try{
+ ByteArrayOutputStream bout=new ByteArrayOutputStream();
+ DataOutputStream dout=new DataOutputStream(bout);
+ writeToStream(dout);
+ size=bout.size();
+ dout.close();
+ bout.close();
+ }catch(Exception e){}
+ }
+
+ /**
+ * Writes the contents of this row to the given RandomAccessFile
+ */
+ public void writeToFile(RandomAccessFile out) throws IOException{
+ long pre=out.getFilePointer();
+
+ out.writeUTF(id);
+
+ Set<String> keys=values.keySet();
+ out.writeInt(keys.size());
+ Iterator<String> it=keys.iterator();
+ while(it.hasNext()){
+ String key=it.next();
+ Value value=values.get(key);
+ out.writeUTF(key);
+ value.writeToFile(out);
+ }
+ long post=out.getFilePointer();
+ int size=(int)(post-pre);
+ this.size=size+4;
+ out.writeInt(this.size);
+ }
+
+ /**
+ * Writes the contents of this row to the given DataOutputStream.
+ */
+ public void writeToStream(DataOutputStream out) throws IOException{
+ int pre=out.size();
+ out.writeUTF(id);
+ Set<String> keys=values.keySet();
+ out.writeInt(keys.size());
+ Iterator<String> it=keys.iterator();
+ while(it.hasNext()){
+ String key=it.next();
+ Value value=values.get(key);
+ out.writeUTF(key);
+ value.writeToStream(out);
+ }
+ int post=out.size();
+ int size=calcSize(pre,post);
+ this.size=size+4;
+ out.writeInt(this.size);
+ }
+
+ /**
+ * Reads a full row from the given DataInputStream and returns it.
+ */
+ public static Row readFromStream(DataInputStream in) throws IOException{
+ String id=in.readUTF();
+ Row row=new Row(id);
+ int size=in.readInt();
+ for(int i=0;i<size;i++){
+ String key=in.readUTF();
+ Value value=Value.readFromStream(in);
+ row.put(key,value);
+ }
+ size=in.readInt();
+ row.size=size;
+ return row;
+ }
+
+ /**
+ * Returns a string representing this row formatted as the following example:
+ * (1732)=>{"name":string:"Kasper J. Jeppesen","age":int:31}
+ *
+ * @return a string representation of this row
+ */
+ public String toString(){
+ StringBuffer buf=new StringBuffer();
+ buf.append("("+id+")=>{");
+ Iterator<String> it=values.keySet().iterator();
+ boolean first=true;
+ while(it.hasNext()){
+ if(!first){
+ buf.append(",");
+ }else{
+ first=false;
+ }
+ String key=it.next();
+ buf.append("\"");
+ buf.append(key);
+ buf.append("\":");
+ Value value=values.get(key);
+ buf.append(value.getTypeName());
+ buf.append(":");
+ if(value.getType()==Value.STRING){
+ buf.append("\"");
+ // TODO: This string should be escaped properly
+ buf.append(value.getString());
+ buf.append("\"");
+ }else{
+ buf.append(value.getString());
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+ /**
+ * Shorthand for calling toBasicXMLString("")
+ */
+ public String toBasicXMLString(){
+ return toBasicXMLString("");
+ }
+
+ /**
+ * Creates an indentation of the given size and calls toBasicXMLString(String) with the indentation string as parameter.
+ */
+ public String toBasicXMLString(int indentation){
+ StringBuffer buf=new StringBuffer();
+ for(int i=0;i<indentation;i++){
+ buf.append(" ");
+ }
+ return toBasicXMLString(buf.toString());
+ }
+
+ /**
+ * Creates a basic xml representation of the row as shown in the following sample:
+ * <row id="1">
+ * <value name="foo" type="string">Bar</value>
+ * </row>
+ */
+ public String toBasicXMLString(String indentation){
+ StringBuffer buf=new StringBuffer();
+ buf.append(indentation);
+ buf.append("<row id=\""+id+"\">\n");
+ Iterator<String> it=values.keySet().iterator();
+ while(it.hasNext()){
+ String key=it.next();
+ Value value=values.get(key);
+ buf.append(indentation);
+ buf.append(" ");
+ buf.append(value.toBasicXMLString(key));
+ buf.append("\n");
+ }
+ buf.append(indentation);
+ buf.append("</row>\n");
+ return buf.toString();
+ }
+ }
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ package com.solidosystems.tuplesoup.core;
+
+ import java.io.*;
+ import java.util.*;
+
+public class RowMatcher{
+ public final static int LESSTHAN=0;
+ public final static int EQUALS=1;
+ public final static int GREATERTHAN=2;
+ public final static int STARTSWITH=3;
+ public final static int ENDSWITH=4;
+ public final static int CONTAINS=5;
+ public final static int ISNULL=6;
+
+ public final static int NOT=7;
+ public final static int OR=8;
+ public final static int AND=9;
+ public final static int XOR=10;
+
+ private String key=null;
+ private Value value=null;
+ private int type=-1;
+
+ private RowMatcher match1=null;
+ private RowMatcher match2=null;
+
+ public RowMatcher(String key,int type,Value value){
+ this.key=key;
+ this.type=type;
+ this.value=value;
+ }
+
+ public RowMatcher(String key,int type){
+ this.key=key;
+ this.type=type;
+ }
+
+ public RowMatcher(RowMatcher match1,int type,RowMatcher match2){
+ this.match1=match1;
+ this.type=type;
+ this.match2=match2;
+ }
+
+ public RowMatcher(int type,RowMatcher match1){
+ this.match1=match1;
+ this.type=type;
+ }
+
+ /**
+ * This method needs to be seriously optimized... especially the XOR method
+ */
+ public boolean matches(Row row){
+ if(value!=null){
+ Value compare=row.get(key);
+ switch(type){
+ case LESSTHAN : return compare.lessThan(value);
+ case EQUALS : return compare.equals(value);
+ case GREATERTHAN: return compare.greaterThan(value);
+ case STARTSWITH : return compare.startsWith(value);
+ case ENDSWITH : return compare.endsWith(value);
+ case CONTAINS : return compare.contains(value);
+ }
+ }else if(type==ISNULL){
+ Value compare=row.get(key);
+ return compare.isNull();
+ }else if((type==AND)||(type==OR)||(type==XOR)){
+ switch(type){
+ case AND : return match1.matches(row)&&match2.matches(row);
+ case OR : return match1.matches(row)||match2.matches(row);
+ case XOR : return (match1.matches(row)||match2.matches(row))&&(!(match1.matches(row)&&match2.matches(row)));
+ }
+ }else if(type==NOT){
+ return !match1.matches(row);
+ }
+ return false;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+import java.nio.channels.*;
+import com.solidosystems.tuplesoup.filter.*;
+
+/**
+ * The table stores a group of rows.
+ * Every row must have a unique id within a table.
+ */
+public interface Table{
+ // Index type constants
+ public static final int MEMORY=0;
+ public static final int FLAT=1;
+ public static final int PAGED=2;
+
+ // Row location constants
+ public static final int FILEA=0;
+ public static final int FILEB=1;
+ public static final int DELETE=2;
+ public static final int INDEX=3;
+
+ /**
+ * Return the current values of the statistic counters and reset them.
+ * The current counters are:
+ * <ul>
+ * <li>stat_table_add
+ * <li>stat_table_update
+ * <li>stat_table_delete
+ * <li>stat_table_add_size
+ * <li>stat_table_update_size
+ * <li>stat_table_read_size
+ * <li>stat_table_read
+ * <li>stat_table_cache_hit
+ * <li>stat_table_cache_miss
+ * <li>stat_table_cache_drop
+ * </ul>
+ * Furthermore, the index will be asked to deliver separate index specific counters
+ */
+ public Hashtable<String,Long> readStatistics();
+
+ /**
+ * Set the maximal allowable size of the index cache.
+ */
+ public void setIndexCacheSize(int newsize);
+
+ /**
+ * Close all open file streams
+ */
+ public void close();
+
+ /**
+ * Returns the name of this table
+ */
+ public String getTitle();
+
+ /**
+ * Returns the location of this tables datafiles
+ */
+ public String getLocation();
+
+ /**
+ * Delete the files created by this table object.
+ * Be aware that this will delete any data stored in this table!
+ */
+ public void deleteFiles();
+
+ /**
+ * Adds a row of data to this table.
+ */
+ public void addRow(Row row) throws IOException;
+
+ /**
+ * Adds a row to this table if it doesn't already exist, if it does it updates the row instead.
+ * This method is much slower than directly using add or update, so only use it if you don't know wether or not the row already exists.
+ */
+ public void addOrUpdateRow(Row row) throws IOException;
+
+ /**
+ * Updates a row stored in this table.
+ */
+ public void updateRow(Row row) throws IOException;
+
+ /**
+ * Marks a row as deleted in the index.
+ * Be aware that the space consumed by the row is not actually reclaimed.
+ */
+ public void deleteRow(Row row) throws IOException;
+
+ /**
+ * Returns a tuplestream containing the given list of rows
+ */
+ public TupleStream getRows(List<String> rows) throws IOException;
+
+ /**
+ * Returns a tuplestream containing the rows matching the given rowmatcher
+ */
+ public TupleStream getRows(RowMatcher matcher) throws IOException;
+
+ /**
+ * Returns a tuplestream containing those rows in the given list that matches the given RowMatcher
+ */
+ public TupleStream getRows(List<String> rows,RowMatcher matcher) throws IOException;
+
+ /**
+ * Returns a tuplestream of all rows in this table.
+ */
+ public TupleStream getRows() throws IOException;
+
+ /**
+ * Returns a single row stored in this table.
+ * If the row does not exist in the table, null will be returned.
+ */
+ public Row getRow(String id) throws IOException;
+ }
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.util.*;
+import java.io.*;
+
+public interface TableIndex{
+ public Hashtable<String,Long> readStatistics();
+ public void updateEntry(String id,int rowsize,int location,long position) throws IOException;
+ public void addEntry(String id,int rowsize,int location,long position) throws IOException;
+ public TableIndexEntry scanIndex(String id) throws IOException;
+ public List<TableIndexEntry> scanIndex(List<String> rows) throws IOException;
+ public List<TableIndexEntry> scanIndex() throws IOException;
+ public void close();
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+
+public class TableIndexEntry implements Comparable<TableIndexEntry>{
+ public String id;
+ public int location;
+ public long position;
+ private int size;
+ private int rowsize;
+
+ public TableIndexEntry(String id,int rowsize,int location,long position){
+ this.id=id;
+ this.location=location;
+ this.position=position;
+ this.rowsize=rowsize;
+ size=-1;
+ }
+ public String getId(){
+ return id;
+ }
+ public void setPosition(long position){
+ this.position=position;
+ }
+ public long getPosition(){
+ return position;
+ }
+ public void setLocation(int location){
+ this.location=location;
+ }
+ public int getLocation(){
+ return location;
+ }
+
+ public int getRowSize(){
+ return rowsize;
+ }
+
+ public int compareTo(TableIndexEntry obj) throws ClassCastException{
+ TableIndexEntry ent=(TableIndexEntry)obj;
+ if(position<ent.position)return -1;
+ if(position==ent.position)return 0;
+ return 1;
+ }
+
+ public boolean equals(Object obj){
+ try{
+ TableIndexEntry ent=(TableIndexEntry)obj;
+ if(ent.location==location){
+ if(ent.position==position){
+ if(ent.id.equals(id)){
+ return true;
+ }
+ }
+ }
+ }catch(ClassCastException e){}
+ return false;
+ }
+
+ public int getSize(){
+ if(size<0)calcSize();
+ return size;
+ }
+ public void setSize(int size){
+ this.size=size;
+ }
+ private void calcSize(){
+ try{
+ ByteArrayOutputStream bout=new ByteArrayOutputStream();
+ DataOutputStream dout=new DataOutputStream(bout);
+ dout.writeInt(id.hashCode());
+ dout.writeShort(id.length());
+ dout.writeChars(id);
+ dout.writeInt(rowsize);
+ dout.writeByte(location);
+ dout.writeLong(position);
+ setSize(bout.size());
+ dout.close();
+ bout.close();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+
+ protected void writeData(RandomAccessFile out) throws IOException{
+ long pre=out.getFilePointer();
+ out.writeInt(id.hashCode());
+ out.writeShort(id.length());
+ out.writeChars(id);
+ out.writeInt(rowsize);
+ out.writeByte(location);
+ out.writeLong(position);
+ setSize((int)(out.getFilePointer()-pre));
+ }
+ protected void updateData(RandomAccessFile out) throws IOException{
+ long pre=out.getFilePointer();
+ out.skipBytes(4+2+id.length()*2);
+ out.writeInt(rowsize);
+ out.writeByte(location);
+ out.writeLong(position);
+ setSize((int)(out.getFilePointer()-pre));
+ }
+ protected void writeData(DataOutputStream out) throws IOException{
+ out.writeInt(id.hashCode());
+ out.writeShort(id.length());
+ out.writeChars(id);
+ out.writeInt(rowsize);
+ out.writeByte(location);
+ out.writeLong(position);
+ }
+ protected static TableIndexEntry readData(RandomAccessFile in) throws IOException{
+ long pre=in.getFilePointer();
+ in.readInt();
+ int num=in.readShort();
+ StringBuilder buf=new StringBuilder(num);
+ for(int i=0;i<num;i++){
+ buf.append(in.readChar());
+ }
+ String id=buf.toString();
+ int rowsize=in.readInt();
+ int location=in.readByte();
+ long position=in.readLong();
+ TableIndexEntry tmp=new TableIndexEntry(id,rowsize,location,position);
+ tmp.setSize((int)(in.getFilePointer()-pre));
+ return tmp;
+ }
+
+ protected static TableIndexEntry readData(DataInputStream in) throws IOException{
+ in.readInt();
+ int num=in.readShort();
+ StringBuilder buf=new StringBuilder(num);
+ for(int i=0;i<num;i++){
+ buf.append(in.readChar());
+ }
+ String id=buf.toString();
+ int rowsize=in.readInt();
+ int location=in.readByte();
+ long position=in.readLong();
+ TableIndexEntry tmp=new TableIndexEntry(id,rowsize,location,position);
+ return tmp;
+ }
+
+ protected static long scanForOffset(String id,DataInputStream in) throws IOException{
+ long offset=0;
+ int scanhash=id.hashCode();
+ try{
+ int datahash=in.readInt();
+ while(scanhash!=datahash){
+ int num=in.readShort();
+ in.skipBytes(1+4+8+num*2);
+ offset+=4+4+1+2+8+num*2;
+ datahash=in.readInt();
+ }
+ return offset;
+ }catch(EOFException e){}
+ return -1;
+ }
+ protected static TableIndexEntry lookForData(String id,DataInputStream in) throws IOException{
+ int scanhash=id.hashCode();
+ int datahash=in.readInt();
+ int num=in.readShort();
+ if(scanhash!=datahash){
+ in.skipBytes(4+1+8+num*2);
+ return null;
+ }
+ StringBuilder buf=new StringBuilder(num);
+ for(int i=0;i<num;i++){
+ buf.append(in.readChar());
+ }
+ String readid=buf.toString();
+ if(!readid.equals(id)){
+ in.skipBytes(4+1+8);
+ return null;
+ }
+ int rowsize=in.readInt();
+ int location=in.readByte();
+ long position=in.readLong();
+ TableIndexEntry tmp=new TableIndexEntry(id,rowsize,location,position);
+ return tmp;
+ }
+ protected static TableIndexEntry lookForData(String id,RandomAccessFile in) throws IOException{
+ int scanhash=id.hashCode();
+ int datahash=in.readInt();
+ int num=in.readShort();
+ if(scanhash!=datahash){
+ in.skipBytes(4+1+8+num*2);
+ return null;
+ }
+ StringBuilder buf=new StringBuilder(num);
+ for(int i=0;i<num;i++){
+ buf.append(in.readChar());
+ }
+ String readid=buf.toString();
+ if(!readid.equals(id)){
+ in.skipBytes(4+1+8);
+ return null;
+ }
+ int rowsize=in.readInt();
+ int location=in.readByte();
+ long position=in.readLong();
+ TableIndexEntry tmp=new TableIndexEntry(id,rowsize,location,position);
+ return tmp;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+public class TableIndexNode{
+ private TableIndexNode previous;
+ private TableIndexEntry data;
+ private TableIndexNode next;
+
+ public TableIndexNode(){
+ previous=null;
+ data=null;
+ next=null;
+ }
+
+ public TableIndexNode(TableIndexEntry entry){
+ previous=null;
+ data=entry;
+ next=null;
+ }
+ public TableIndexNode(TableIndexNode prev,TableIndexEntry entry){
+ previous=prev;
+ data=entry;
+ next=null;
+ }
+ public TableIndexNode(TableIndexNode prev,TableIndexEntry entry,TableIndexNode nex){
+ previous=prev;
+ data=entry;
+ next=nex;
+ }
+
+ public TableIndexEntry getData(){
+ return data;
+ }
+ public TableIndexNode getPrevious(){
+ return previous;
+ }
+ public TableIndexNode getNext(){
+ return next;
+ }
+ public void setNext(TableIndexNode node){
+ next=node;
+ }
+ public void setPrevious(TableIndexNode node){
+ previous=node;
+ }
+ public void setData(TableIndexEntry entry){
+ data=entry;
+ }
+ public void remove(){
+ if(previous!=null){
+ previous.setNext(next);
+ }
+ if(next!=null){
+ next.setPrevious(previous);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+
+public class TableIndexPage{
+ private final static int BASEOFFSET=4+8+8+4+4;
+ private RandomAccessFile file=null;
+
+ private long location=-1;
+ private int size=-1;
+ private long next=-1;
+ private long lower=-1;
+ private int offset=0;
+
+ private int starthash=-1;
+ private int endhash=-1;
+ private boolean first=false;
+
+ private TableIndexPage nextpage=null;
+ private TableIndexPage lowerpage=null;
+
+ private PagedIndex index=null;
+
+ public TableIndexPage(PagedIndex index,RandomAccessFile file) throws IOException{
+ this.file=file;
+ this.index=index;
+ first=false;
+ location=file.getFilePointer();
+ size=file.readInt();
+ next=file.readLong();
+ lower=file.readLong();
+ offset=file.readInt();
+ endhash=file.readInt();
+ if(offset>0)starthash=file.readInt();
+ }
+
+ public static TableIndexPage createNewPage(PagedIndex index,RandomAccessFile file,int size) throws IOException{
+ long pre=file.length();
+ file.setLength(file.length()+size+BASEOFFSET);
+ file.seek(pre);
+ file.writeInt(size);
+ file.writeLong(-1l);
+ file.writeLong(-1l);
+ file.writeInt(0);
+ file.writeInt(-1);
+ file.seek(pre);
+ index.stat_create_page++;
+ return new TableIndexPage(index,file);
+ }
+
+ public void setFirst(){
+ first=true;
+ }
+
+ public long getLocation(){
+ return location;
+ }
+ public long getEndLocation(){
+ return location+size+BASEOFFSET;
+ }
+
+ public String toString(){
+ StringBuffer buf=new StringBuffer();
+ buf.append("{\n");
+ buf.append(" location "+location+"\n");
+ buf.append(" size "+size+"\n");
+ buf.append(" next "+next+"\n");
+ buf.append(" lower "+lower+"\n");
+ buf.append(" offset "+offset+"\n");
+ buf.append(" starthash "+starthash+"\n");
+ buf.append(" endhash "+endhash+"\n");
+ buf.append("}\n");
+ return buf.toString();
+ }
+
+ private void updateMeta() throws IOException{
+ file.seek(location);
+ file.writeInt(size);
+ file.writeLong(next);
+ file.writeLong(lower);
+ file.writeInt(offset);
+ file.writeInt(endhash);
+ }
+
+ public void addEntriesToList(List<TableIndexEntry> lst) throws IOException{
+ if(lower>-1){
+ if(lowerpage==null){
+ file.seek(lower);
+ lowerpage=new TableIndexPage(index,file);
+ }
+ lowerpage.addEntriesToList(lst);
+ }
+ if(next>-1){
+ if(nextpage==null){
+ file.seek(next);
+ nextpage=new TableIndexPage(index,file);
+ }
+ nextpage.addEntriesToList(lst);
+ }
+ file.seek(location+BASEOFFSET);
+ long pre=file.getFilePointer();
+ while(file.getFilePointer()<pre+offset){
+ TableIndexEntry entry=TableIndexEntry.readData(file);
+ if(entry!=null){
+ if(entry.getLocation()!=Table.DELETE)lst.add(entry);
+ }
+ }
+ }
+
+ public TableIndexEntry scanIndex(String id,int hashcode) throws IOException{
+ if(!first){
+ if(hashcode<starthash){
+ if(lower==-1)return null;
+ if(lowerpage==null){
+ file.seek(lower);
+ lowerpage=new TableIndexPage(index,file);
+ }
+ index.stat_page_branch++;
+ return lowerpage.scanIndex(id,hashcode);
+ }
+ }
+ if(hashcode>endhash){
+ if(next==-1)return null;
+ if(nextpage==null){
+ file.seek(next);
+ nextpage=new TableIndexPage(index,file);
+ }
+ index.stat_page_next++;
+ return nextpage.scanIndex(id,hashcode);
+ }
+ file.seek(location+BASEOFFSET);
+ long pre=file.getFilePointer();
+ while(file.getFilePointer()<pre+offset){
+ TableIndexEntry entry=TableIndexEntry.lookForData(id,file);
+ if(entry!=null)return entry;
+ }
+ if(next==-1)return null;
+ if(nextpage==null){
+ file.seek(next);
+ nextpage=new TableIndexPage(index,file);
+ }
+ index.stat_page_next++;
+ return nextpage.scanIndex(id,hashcode);
+ }
+ protected long getOffset(String id,int hashcode) throws IOException{
+ if(!first){
+ if(hashcode<starthash){
+ if(lower==-1)return -1;
+ if(lowerpage==null){
+ file.seek(lower);
+ lowerpage=new TableIndexPage(index,file);
+ }
+ index.stat_page_branch++;
+ return lowerpage.getOffset(id,hashcode);
+ }
+ }
+ if(hashcode>endhash){
+ if(next==-1)return -1;
+ if(nextpage==null){
+ file.seek(next);
+ nextpage=new TableIndexPage(index,file);
+ }
+ index.stat_page_next++;
+ return nextpage.getOffset(id,hashcode);
+ }
+ file.seek(location+BASEOFFSET);
+ long pre=file.getFilePointer();
+ while(file.getFilePointer()<pre+offset){
+ long prescan=file.getFilePointer();
+ TableIndexEntry entry=TableIndexEntry.lookForData(id,file);
+ if(entry!=null)return prescan;
+ }
+ if(next==-1)return -1;
+ if(nextpage==null){
+ file.seek(next);
+ nextpage=new TableIndexPage(index,file);
+ }
+ index.stat_page_next++;
+ return nextpage.getOffset(id,hashcode);
+ }
+
+ protected TableIndexPage getFirstFreePage(String id,int hashcode) throws IOException{
+ // Is this an empty page?
+ if(offset==0){
+ return this;
+ }
+ // Is this hash lower than the starthash
+ if(!first){
+ if(hashcode<starthash){
+ if(lower==-1){
+ lower=file.length();
+ updateMeta();
+ return createNewPage(index,file,PagedIndex.PAGESIZE);
+ }
+ if(lowerpage==null){
+ file.seek(lower);
+ lowerpage=new TableIndexPage(index,file);
+ }
+ index.stat_page_branch++;
+ return lowerpage.getFirstFreePage(id,hashcode);
+ }
+ }
+ // Do we have space in this page
+ if(size-offset>id.length()*2+4+4+8+1+2)return this;
+ // Check next
+ if(next==-1){
+ next=file.length();
+ updateMeta();
+ return createNewPage(index,file,PagedIndex.PAGESIZE);
+ }
+ if(nextpage==null){
+ file.seek(next);
+ nextpage=new TableIndexPage(index,file);
+ }
+ index.stat_page_next++;
+ return nextpage.getFirstFreePage(id,hashcode);
+ }
+
+ public void addEntry(String id,int rowsize,int location,long position) throws IOException{
+ if(offset==0)starthash=id.hashCode();
+ file.seek(this.location+BASEOFFSET+offset);
+ TableIndexEntry entry=new TableIndexEntry(id,rowsize,location,position);
+ entry.writeData(file);
+ offset+=entry.getSize();
+ if(id.hashCode()>endhash)endhash=id.hashCode();
+ updateMeta();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+
+public abstract class TupleStream{
+ public abstract boolean hasNext() throws IOException;
+ public abstract Row next() throws IOException;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+
+public class TupleStreamMerger extends TupleStream{
+ private List<TupleStream> streams;
+ private TupleStream current=null;
+ private Row next=null;
+
+ public TupleStreamMerger(){
+ streams=new ArrayList<TupleStream>();
+ }
+
+ public void addStream(TupleStream stream){
+ streams.add(stream);
+ }
+
+ public boolean hasNext() throws IOException{
+ if(next!=null)return true;
+ if(current==null){
+ if(streams.size()>0){
+ current=streams.remove(0);
+ }else return false;
+ }
+ if(current.hasNext()){
+ next=current.next();
+ return true;
+ }else{
+ current=null;
+ return hasNext();
+ }
+ }
+
+ public Row next() throws IOException{
+ if(next==null)hasNext();
+ Row tmp=next;
+ next=null;
+ return tmp;
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ package com.solidosystems.tuplesoup.core;
+
+ import java.util.*;
+ import java.io.*;
+
+ /**
+ * The Value class holds a single data value.
+ * Current size estimate without string data: 8+4+4+8+8 = 32 bytes pr value in mem
+ */
+ public class Value{
+ public final static int NULL=0;
+ public final static int STRING=1;
+ public final static int INT=2;
+ public final static int LONG=3;
+ public final static int FLOAT=4;
+ public final static int DOUBLE=5;
+ public final static int BOOLEAN=6;
+ public final static int TIMESTAMP=7;
+ public final static int BINARY=8;
+
+ private byte type=NULL; // The type of the value being held
+ private String str_value=null;
+ private long int_value=0;
+ private double float_value=0.0;
+ private byte[] binary=null;
+
+ /**
+ * Returns the numerical type id for this value.
+ */
+ public int getType(){
+ return type;
+ }
+
+ /**
+ * Returns the name this value's type.
+ */
+ public String getTypeName(){
+ switch(type){
+ case STRING : return "string";
+ case INT : return "int";
+ case LONG : return "long";
+ case FLOAT : return "float";
+ case DOUBLE : return "double";
+ case BOOLEAN : return "boolean";
+ case TIMESTAMP : return "timestamp";
+ case BINARY : return "binary";
+ }
+ return "null";
+ }
+
+ /**
+ * An implementation of the hashCode method as defined in java.lang.Object
+ *
+ * @return a hash code value for this object
+ */
+ public int hashCode(){
+ int hash=0;
+ switch(type){
+ case STRING : hash+=str_value.hashCode();
+ case INT : hash+=(int)int_value;
+ case LONG : hash+=(int)int_value;
+ case FLOAT : hash+=(int)float_value;
+ case DOUBLE : hash+=(int)float_value;
+ case BOOLEAN : hash+=(int)int_value;
+ case TIMESTAMP : hash+=(int)int_value;
+ case BINARY : hash+=binary.hashCode();
+ }
+ return hash;
+ }
+
+ /**
+ * Returns true only if this Value has specifically been set to null.
+ *
+ * @return true if the data being held is null, false otherwise
+ */
+ public boolean isNull(){
+ return type==NULL;
+ }
+
+ /**
+ * Returns -1, 0 or 1 if this value is smaller, equal or larger than the value given as a parameter.
+ */
+ public int compareTo(Value value){
+ if(type==STRING){
+ return str_value.compareTo(value.getString());
+ }
+ if(lessThan(value))return -1;
+ if(greaterThan(value))return 1;
+ return 0;
+ }
+
+ /**
+ * Attempts to compare this Value to the value given as parameter and returns true if this value is less than the value given as a parameter.
+ * The types used for the comparison will always be based on the type of this Value based on the following rules.
+ * <ul>
+ * <li>If this Value is a numeric type, then the other Value will be asked to deliver the same numeric type for the comparison.
+ * <li>If this Value is a string, then both values will be asked to deliver a double value for the comparison.
+ * <li>If this Value is a timestamp, then both values will be asked to deliver a long value for the comparison.
+ * <li>If this Value is a boolean, false will be returned.
+ * </ul>
+ *
+ * @param value the value this value should be compared to
+ * @return true if this value is less than the value given as a parameter, false otherwise
+ */
+ public boolean lessThan(Value value){
+ switch(type){
+ case STRING : return getDouble()<value.getDouble();
+ case INT : return getInt()<value.getInt();
+ case LONG : return getLong()<value.getLong();
+ case FLOAT : return getFloat()<value.getFloat();
+ case DOUBLE : return getDouble()<value.getDouble();
+ case TIMESTAMP : return getLong()<value.getLong();
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to compare this Value to the value given as parameter and returns true if this value is greater than the value given as a parameter.
+ * The types used for the comparison will always be based on the type of this Value based on the following rules.
+ * <ul>
+ * <li>If this Value is a numeric type, then the other Value will be asked to deliver the same numeric type for the comparison.
+ * <li>If this Value is a string, then both values will be asked to deliver a double value for the comparison.
+ * <li>If this Value is a timestamp, then both values will be asked to deliver a long value for the comparison.
+ * <li>If this Value is a boolean, false will be returned.
+ * </ul>
+ *
+ * @param value the value this value should be compared to
+ * @return true if this value is greater than the value given as a parameter, false otherwise
+ */
+ public boolean greaterThan(Value value){
+ switch(type){
+ case STRING : return getDouble()>value.getDouble();
+ case INT : return getInt()>value.getInt();
+ case LONG : return getLong()>value.getLong();
+ case FLOAT : return getFloat()>value.getFloat();
+ case DOUBLE : return getDouble()>value.getDouble();
+ case TIMESTAMP : return getLong()>value.getLong();
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the string representation of this value starts with the string representation of the value given as parameter.
+ */
+ public boolean startsWith(Value value){
+ return getString().startsWith(value.getString());
+ }
+
+ /**
+ * Returns true if the string representation of this value ends with the string representation of the value given as parameter.
+ */
+ public boolean endsWith(Value value){
+ return getString().endsWith(value.getString());
+ }
+
+ /**
+ * Returns true if the string representation of this value contains the string representation of the value given as parameter.
+ */
+ public boolean contains(Value value){
+ return getString().indexOf(value.getString())>-1;
+ }
+
+ /**
+ * Returns true if the contents of this value equals the contents of the value given as parameter.
+ */
+ public boolean equals(Object obj){
+ try{
+ Value val=(Value)obj;
+ if(val.type==type){
+ switch(type){
+ case NULL : return true;
+ case STRING : return str_value.equals(val.str_value);
+ case INT : return int_value==val.int_value;
+ case LONG : return int_value==val.int_value;
+ case FLOAT : return float_value==val.float_value;
+ case DOUBLE : return float_value==val.float_value;
+ case BOOLEAN : return int_value==val.int_value;
+ case TIMESTAMP : return int_value==val.int_value;
+ case BINARY : if(binary.length==val.binary.length){
+ for(int i=0;i<binary.length;i++){
+ if(binary[i]!=val.binary[i])return false;
+ }
+ }
+ return true;
+ }
+ }
+ }catch(Exception e){}
+ return false;
+ }
+
+ /**
+ * Returns a string representation of this object.
+ */
+ public String toString(){
+ return getString();
+ }
+
+ /**
+ * Returns a string representation of this object (identical to toString)
+ */
+ public String get(){
+ return getString();
+ }
+
+ /**
+ * Returns this value as an xml tag with the given key set as an attribute called name.
+ * The following string is an example of the int value 1234 created with the key foo <value name="foo" type="int">1234</value>
+ */
+ public String toBasicXMLString(String key){
+ switch(type){
+ case STRING : return "<value name=\""+key+"\" type=\"string\">"+str_value+"</value>";
+ case INT : return "<value name=\""+key+"\" type=\"int\">"+int_value+"</value>";
+ case LONG : return "<value name=\""+key+"\" type=\"long\">"+int_value+"</value>";
+ case FLOAT : return "<value name=\""+key+"\" type=\"float\">"+float_value+"</value>";
+ case DOUBLE : return "<value name=\""+key+"\" type=\"double\">"+float_value+"</value>";
+ case BOOLEAN : if(int_value==1){
+ return "<value name=\""+key+"\" type=\"boolean\">TRUE</value>";
+ }else{
+ return "<value name=\""+key+"\" type=\"boolean\">FALSE</value>";
+ }
+ case TIMESTAMP : return "<value name=\""+key+"\" type=\"timestamp\">"+new Date(int_value).toString()+"</value>";
+ case BINARY : return "<value name=\""+key+"\" type=\"binary\">"+getString()+"</value>";
+ }
+ return "<value name=\""+key+"\" type=\"null\"></value>";
+ }
+
+ /**
+ * Returns this value as an xml tag.
+ * The following string is an example of the int value 1234 <value type="int">1234</value>
+ */
+ public String toBasicXMLString(){
+ switch(type){
+ case STRING : return "<value type=\"string\">"+str_value+"</value>";
+ case INT : return "<value type=\"int\">"+int_value+"</value>";
+ case LONG : return "<value type=\"long\">"+int_value+"</value>";
+ case FLOAT : return "<value type=\"float\">"+float_value+"</value>";
+ case DOUBLE : return "<value type=\"double\">"+float_value+"</value>";
+ case BOOLEAN : if(int_value==1){
+ return "<value type=\"boolean\">TRUE</value>";
+ }else{
+ return "<value type=\"boolean\">FALSE</value>";
+ }
+ case TIMESTAMP : return "<value type=\"timestamp\">"+new Date(int_value).toString()+"</value>";
+ case BINARY : return "<value type=\"binary\">"+getString()+"</value>";
+ }
+ return "<value type=\"null\"></value>";
+ }
+
+ /**
+ * Returns a string representation of this value
+ */
+ public String getString(){
+ switch(type){
+ case STRING : return str_value;
+ case INT : return ""+int_value;
+ case LONG : return ""+int_value;
+ case FLOAT : return ""+float_value;
+ case DOUBLE : return ""+float_value;
+ case BOOLEAN : if(int_value==1){
+ return "TRUE";
+ }else{
+ return "FALSE";
+ }
+ case TIMESTAMP : return new Date(int_value).toString();
+ case BINARY : StringBuffer buf=new StringBuffer();
+ for(int i=0;i<binary.length;i++){
+ byte b=binary[i];
+ buf.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1,3));
+ }
+ return buf.toString();
+ }
+ return "";
+ }
+
+ /**
+ * Attempts to return an integer representation of this value.
+ * Numerical values will be returned directly (demoted if necessary).
+ * Boolean values will be returned as 1 or 0.
+ * Timestamp values will be returned as a unix timestamp representation divided by 1000.
+ * String values will be atempted to be converted into an int, if that fails, 0 will be returned.
+ * Everything else will return 0.
+ */
+ public int getInt(){
+ try{
+ switch(type){
+ case STRING : return Integer.parseInt(str_value);
+ case INT : return (int)int_value;
+ case LONG : return (int)int_value;
+ case FLOAT : return (int)float_value;
+ case DOUBLE : return (int)float_value;
+ case BOOLEAN : return (int)int_value;
+ case TIMESTAMP : return (int)(int_value/1000);
+ }
+ }catch(Exception e){}
+ return 0;
+ }
+
+ /**
+ * Attempts to return a long representation of this value.
+ * Numerical values will be returned directly.
+ * Boolean values will be returned as 1 or 0.
+ * Timestamp values will be returned as a unix timestamp representation.
+ * String values will be atempted to be converted into an int, if that fails, 0 will be returned.
+ * Everything else will return 0.
+ */
+ public long getLong(){
+ try{
+ switch(type){
+ case STRING : return Long.parseLong(str_value);
+ case INT : return int_value;
+ case LONG : return int_value;
+ case FLOAT : return (long)float_value;
+ case DOUBLE : return (long)float_value;
+ case BOOLEAN : return int_value;
+ case TIMESTAMP : return int_value;
+ }
+ }catch(Exception e){}
+ return 0;
+ }
+
+ /**
+ * Attempts to return a float representation of this value.
+ * Numerical values will be returned directly (demoted if necessary).
+ * Boolean values will be returned as 1 or 0.
+ * Timestamp values will be returned as a unix timestamp representation divided by 1000.
+ * String values will be atempted to be converted into a float, if that fails, 0 will be returned.
+ * Everything else will return 0.
+ */
+ public float getFloat(){
+ try{
+ switch(type){
+ case STRING : return Float.parseFloat(str_value);
+ case INT : return (float)int_value;
+ case LONG : return (float)int_value;
+ case FLOAT : return (float)float_value;
+ case DOUBLE : return (float)float_value;
+ case BOOLEAN : return (float)int_value;
+ case TIMESTAMP : return (float)(int_value/1000);
+ }
+ }catch(Exception e){}
+ return 0.0f;
+ }
+
+ /**
+ * Attempts to return a double representation of this value.
+ * Numerical values will be returned directly.
+ * Boolean values will be returned as 1 or 0.
+ * Timestamp values will be returned as a unix timestamp representation divided by 1000.
+ * String values will be atempted to be converted into a float, if that fails, 0 will be returned.
+ * Everything else will return 0.
+ */
+ public double getDouble(){
+ try{
+ switch(type){
+ case STRING : return Double.parseDouble(str_value);
+ case INT : return (double)int_value;
+ case LONG : return (double)int_value;
+ case FLOAT : return (double)float_value;
+ case DOUBLE : return (double)float_value;
+ case BOOLEAN : return (double)int_value;
+ case TIMESTAMP : return (double)(int_value);
+ }
+ }catch(Exception e){}
+ return 0.0;
+ }
+
+ /**
+ * Returns a boolean representation of this value.
+ * Boolean values will be returned directly.
+ * Integer values equalling 1 will be returned as true.
+ * String values equalling true,1,t,yes,on will be returned as true (case insensitive).
+ * Everything else will be returned as false.
+ *
+ * @return a boolean representation of this value.
+ */
+ public boolean getBoolean(){
+ try{
+ switch(type){
+ case STRING : if(str_value.toLowerCase().trim().equals("true"))return true;
+ if(str_value.trim().equals("1"))return true;
+ if(str_value.toLowerCase().trim().equals("t"))return true;
+ if(str_value.toLowerCase().trim().equals("yes"))return true;
+ if(str_value.toLowerCase().trim().equals("on"))return true;
+ case INT : if(int_value==1)return true;
+ case LONG : if(int_value==1)return true;
+ case FLOAT : if(float_value==1.0f)return true;
+ case DOUBLE : if(float_value==1.0)return true;
+ case BOOLEAN : if(int_value==1)return true;
+ }
+ }catch(Exception e){}
+ return false;
+ }
+
+ /**
+ * Attempts to return this value as a Date object.
+ * For non date numerical values, the following rules will be used for conversion:
+ * int and float will be multiplied by 1000 and used as a unix timestamp.
+ * long and double will be used directly as a unix timestamp.
+ * Any other type will result in a Date object initialized with 0.
+ *
+ * @return a Date object representation of this value
+ */
+ public Date getTimestamp(){
+ try{
+ switch(type){
+ case INT : return new Date(int_value*1000l);
+ case LONG : return new Date(int_value);
+ case FLOAT : return new Date((long)(float_value*1000l));
+ case DOUBLE : return new Date((long)float_value);
+ case TIMESTAMP : return new Date(int_value);
+ }
+ }catch(Exception e){}
+ return new Date(0);
+ }
+
+ public byte[] getBinary(){
+ switch(type){
+ case BINARY : return binary;
+ }
+ return null;
+ }
+
+ /**
+ * Attempts to write this Value to the given DataOutputStream.
+ * The Value will be written as a byte signifying the type of the Value, followed by the actual Value in the native format used by DataOutput.
+ * The exception to this is the string which is written as an integer followed by each character as a single char.
+ *
+ * @param out the DataOutputStream the Value should be written to
+ */
+ public void writeToStream(DataOutputStream out) throws IOException{
+ out.writeByte(type);
+ switch(type){
+ case STRING : out.writeInt(str_value.length());
+ for(int i=0;i<str_value.length();i++){
+ out.writeChar(str_value.charAt(i));
+ }
+ break;
+ case INT : out.writeInt((int)int_value);
+ break;
+ case LONG : out.writeLong(int_value);
+ break;
+ case FLOAT : out.writeFloat((float)float_value);
+ break;
+ case DOUBLE : out.writeDouble(float_value);
+ break;
+ case BOOLEAN: out.writeBoolean(int_value==1);
+ break;
+ case TIMESTAMP: out.writeLong(int_value);
+ break;
+ case BINARY : out.writeInt(binary.length);
+ out.write(binary,0,binary.length);
+ break;
+ }
+ }
+
+ /**
+ * Attempts to write this Value to the given DataOutputStream.
+ * The Value will be written as a byte signifying the type of the Value, followed by the actual Value in the native format used by DataOutput.
+ * The exception to this is the string which is written as an integer followed by each character as a single char.
+ *
+ * @param out the DataOutputStream the Value should be written to
+ */
+ public void writeToFile(DataOutput out) throws IOException{
+ out.writeByte(type);
+ switch(type){
+ case STRING : out.writeInt(str_value.length());
+ for(int i=0;i<str_value.length();i++){
+ out.writeChar(str_value.charAt(i));
+ }
+ break;
+ case INT : out.writeInt((int)int_value);
+ break;
+ case LONG : out.writeLong(int_value);
+ break;
+ case FLOAT : out.writeFloat((float)float_value);
+ break;
+ case DOUBLE : out.writeDouble(float_value);
+ break;
+ case BOOLEAN: out.writeBoolean(int_value==1);
+ break;
+ case TIMESTAMP: out.writeLong(int_value);
+ break;
+ case BINARY : out.writeInt(binary.length);
+ out.write(binary,0,binary.length);
+ }
+ }
+
+ /**
+ * Attempts to read a new Value from the given DataInputStream.
+ * The Value should be in the format delivered by writeToStream.
+ *
+ * @param in the DataInputStream the Value should be read from
+ * @return the Value read from the stream
+ */
+ public static Value readFromStream(DataInputStream in) throws IOException{
+ byte type=in.readByte();
+ switch(type){
+ case STRING : int size=in.readInt();
+ StringBuffer buf=new StringBuffer();
+ for(int i=0;i<size;i++){
+ buf.append(in.readChar());
+ }
+ return new Value(buf.toString());
+ case INT : return new Value(in.readInt());
+ case LONG : return new Value(in.readLong());
+ case FLOAT : return new Value(in.readFloat());
+ case DOUBLE : return new Value(in.readDouble());
+ case BOOLEAN: return new Value(in.readBoolean());
+ case TIMESTAMP: return new Value(new Date(in.readLong()));
+ case BINARY : int length=in.readInt();
+ byte[] abuf=new byte[length];
+ int read=0;
+ while(read<length){
+ read+=in.read(abuf,read,length-read);
+ }
+ return new Value(abuf);
+
+ }
+ return new Value();
+ }
+
+ /**
+ * Initializes this Value with the given String.
+ *
+ * @param val the value this Value object should represent
+ */
+ public Value(String val){
+ str_value=val;
+ type=STRING;
+ }
+
+ public Value(byte[] val){
+ binary=val;
+ type=BINARY;
+ }
+
+ /**
+ * Initializes this Value with the given Date.
+ * The Dates internal long value delivered by the getTime() method will be used.
+ *
+ * @param val the value this Value object should represent
+ */
+ public Value(Date val){
+ int_value=val.getTime();
+ type=TIMESTAMP;
+ }
+
+ /**
+ * Initializes this Value as null.
+ */
+ public Value(){
+ type=NULL;
+ }
+
+ /**
+ * Initializes this Value with the given int.
+ *
+ * @param val the value this Value object should represent
+ */
+ public Value(int val){
+ int_value=val;
+ type=INT;
+ }
+
+ /**
+ * Initializes this Value with the given long.
+ *
+ * @param val the value this Value object should represent
+ */
+ public Value(long val){
+ int_value=val;
+ type=LONG;
+ }
+
+ /**
+ * Initializes this Value with the given float.
+ *
+ * @param val the value this Value object should represent
+ */
+ public Value(float val){
+ float_value=val;
+ type=FLOAT;
+ }
+
+ /**
+ * Initializes this Value with the given double.
+ *
+ * @param val the value this Value object should represent
+ */
+ public Value(double val){
+ float_value=val;
+ type=DOUBLE;
+ }
+
+ /**
+ * Initializes this Value with the given boolean.
+ *
+ * @param val the value this Value object should represent
+ */
+ public Value(boolean val){
+ if(val){
+ int_value=1;
+ }else{
+ int_value=0;
+ }
+ type=BOOLEAN;
+ }
+ }
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class Conditional extends TupleStream{
+ private TupleStream stream;
+ private RowMatcher matcher;
+ private Row next;
+
+ public Conditional(TupleStream stream, RowMatcher matcher) throws IOException{
+ this.stream=stream;
+ this.matcher=matcher;
+ next=null;
+ readNext();
+ }
+
+ private void readNext() throws IOException{
+ next=null;
+ while(next==null){
+ if(!stream.hasNext())return;
+ Row row=stream.next();
+ if(matcher.matches(row)){
+ next=row;
+ }
+ }
+ }
+
+ public boolean hasNext() throws IOException{
+ if(next!=null)return true;
+ return false;
+ }
+
+ public Row next() throws IOException{
+ Row tmp=next;
+ readNext();
+ return tmp;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+
+public abstract class HeapSort extends TupleStream{
+ public HeapSort(){
+
+ }
+ public void initialize(TupleStream source,List<SortRule> lst){
+
+ }
+ public abstract boolean hasNext();
+ public abstract Row next();
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class JavaSort extends Sort{
+ private List<Row> sortlst;
+ private int offset;
+ private int datasize;
+
+ public JavaSort(){
+ }
+ public void initialize(String filename,TupleStream source,List<SortRule> lst) throws IOException{
+ sortlst=new ArrayList<Row>();
+ offset=0;
+ while(source.hasNext()){
+ sortlst.add(source.next());
+ }
+ Collections.sort(sortlst,new SortComparator(lst));
+ datasize=sortlst.size();
+ }
+ public boolean hasNext(){
+ if(offset<datasize)return true;
+ return false;
+ }
+ public Row next(){
+ return sortlst.get(offset++);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class Join extends TupleStream{
+ public final static int INNER=0;
+
+ private int type;
+ private TupleStream left;
+ private TupleStream right;
+ private String key;
+ private RowBuffer buf;
+ private String filename;
+
+ public Join(String filename,TupleStream left, TupleStream right, String key) throws IOException{
+ this.filename=filename;
+ this.left=left;
+ this.right=right;
+ this.key=key;
+ this.type=INNER;
+ joinData();
+ }
+
+ public Join(String filename,TupleStream left, TupleStream right, String key,int type) throws IOException{
+ this.filename=filename;
+ this.left=left;
+ this.right=right;
+ this.key=key;
+ this.type=type;
+ joinData();
+ }
+
+ private void joinData() throws IOException{
+ buf=new RowBuffer(filename);
+ // Raw nested loop operation
+
+ buf.prepare();
+ }
+
+ public Row next() throws IOException{
+ return buf.next();
+ }
+
+ public boolean hasNext() throws IOException{
+ return buf.hasNext();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class MergeSort extends Sort{
+ private int MEMLIMIT=65536;
+ private int BUFFERCACHE=65536;
+ private int BUFFERLIMIT=8192;
+
+ private RowBuffer result;
+
+ private int bufnum=0;
+
+ private String filename;
+
+ private SortComparator compare;
+
+
+ public MergeSort(int cachesize){
+ if(cachesize<32768){
+ MEMLIMIT=32768;
+ BUFFERCACHE=0;
+ BUFFERLIMIT=0;
+ }else if(cachesize<65536){
+ MEMLIMIT=32768;
+ BUFFERCACHE=cachesize-MEMLIMIT;
+ BUFFERLIMIT=BUFFERCACHE/4;
+ }else{
+ MEMLIMIT=cachesize/2;
+ BUFFERCACHE=MEMLIMIT;
+ BUFFERLIMIT=BUFFERCACHE/16;
+ }
+ if(BUFFERLIMIT<8192)BUFFERLIMIT=8192;
+ }
+
+ public void mergeSort(RowBuffer result,RowBuffer a,RowBuffer b) throws IOException{
+ a.prepare();
+ b.prepare();
+ Row rowb=null;
+ Row rowa=null;
+ while(a.hasNext()&&b.hasNext()){
+ if(rowa==null)rowa=a.next();
+ if(rowb==null)rowb=b.next();
+ int cmp=compare.compare(rowa,rowb);
+ if(cmp<=0){
+ result.addRow(rowa);
+ rowa=null;
+ }else{
+ result.addRow(rowb);
+ rowb=null;
+ }
+ }
+ if(rowa!=null)result.addRow(rowa);
+ if(rowb!=null)result.addRow(rowb);
+ while(a.hasNext()){
+ result.addRow(a.next());
+ }
+ while(b.hasNext()){
+ result.addRow(b.next());
+ }
+ }
+
+ public void mergeSort(List<RowBuffer> buffers) throws IOException{
+ while(buffers.size()>2){
+ RowBuffer tmp=new RowBuffer(filename+"."+(bufnum++));
+ tmp.setCacheSize(allocBuffer());
+ // Grab two and sort to buf
+ RowBuffer a=buffers.remove(0);
+ RowBuffer b=buffers.remove(0);
+ mergeSort(tmp,a,b);
+ a.close();
+ freeBuffer(a);
+ b.close();
+ freeBuffer(b);
+ buffers.add(tmp);
+ }
+ if(buffers.size()==1){
+ result.close();
+ result=buffers.get(0);
+ result.prepare();
+ return;
+ }
+ if(buffers.size()==2){
+ RowBuffer a=buffers.get(0);
+ RowBuffer b=buffers.get(1);
+ mergeSort(result,a,b);
+ a.close();
+ freeBuffer(a);
+ b.close();
+ freeBuffer(b);
+ result.prepare();
+ return;
+ }
+ }
+
+ private int allocBuffer(){
+ if(BUFFERCACHE>=BUFFERLIMIT){
+ BUFFERCACHE-=BUFFERLIMIT;
+ return BUFFERLIMIT;
+ }
+ int tmp=BUFFERCACHE;
+ BUFFERCACHE=0;
+ return tmp;
+ }
+ private void freeBuffer(RowBuffer buf){
+ BUFFERCACHE+=buf.getCacheSize();
+ }
+
+ public void initialize(String filename,TupleStream source,List<SortRule> lst) throws IOException{
+ this.filename=filename;
+ compare=new SortComparator(lst);
+ bufnum=0;
+ result=new RowBuffer(filename+".result");
+ result.setCacheSize(BUFFERLIMIT);
+ List<RowBuffer> buffers=new ArrayList<RowBuffer>();
+ int usage=0;
+ List<Row> sortlst=new ArrayList<Row>();
+ while(source.hasNext()){
+ Row row=source.next();
+ if(usage+row.getSize()>MEMLIMIT){
+ RowBuffer buf=new RowBuffer(filename+"."+(bufnum++));
+ buf.setCacheSize(allocBuffer());
+ Collections.sort(sortlst,new SortComparator(lst));
+ for(int i=0;i<sortlst.size();i++){
+ buf.addRow(sortlst.get(i));
+ }
+ buffers.add(buf);
+ usage=0;
+ sortlst=new ArrayList<Row>();
+ }
+ sortlst.add(row);
+ usage+=row.getSize();
+ }
+ RowBuffer buf=new RowBuffer(filename+"."+(bufnum++));
+ buf.setCacheSize(allocBuffer());
+ Collections.sort(sortlst,new SortComparator(lst));
+ for(int i=0;i<sortlst.size();i++){
+ buf.addRow(sortlst.get(i));
+ }
+ buffers.add(buf);
+ mergeSort(buffers);
+ }
+ public boolean hasNext() throws IOException{
+ return result.hasNext();
+ }
+ public Row next() throws IOException{
+ return result.next();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class MergeSort2 extends Sort{
+ private int MEMLIMIT=65536;
+ private int BUFFERCACHE=65536;
+ private int BUFFERLIMIT=8192;
+
+ private int PREBUFFERS=256;
+
+ private RowBuffer result;
+
+ private int bufnum=0;
+
+ private String filename;
+
+ private SortComparator compare;
+
+
+ public MergeSort2(int cachesize){
+ if(cachesize<32768){
+ MEMLIMIT=32768;
+ BUFFERCACHE=0;
+ BUFFERLIMIT=0;
+ }else if(cachesize<65536){
+ MEMLIMIT=32768;
+ BUFFERCACHE=cachesize-MEMLIMIT;
+ BUFFERLIMIT=BUFFERCACHE/4;
+ }else{
+ MEMLIMIT=cachesize/2;
+ BUFFERCACHE=MEMLIMIT;
+ BUFFERLIMIT=BUFFERCACHE/16;
+ }
+ if(BUFFERLIMIT<8192)BUFFERLIMIT=8192;
+ }
+
+ public void mergeSort(RowBuffer result,RowBuffer a,RowBuffer b) throws IOException{
+ a.prepare();
+ b.prepare();
+ Row rowb=null;
+ Row rowa=null;
+ while(a.hasNext()&&b.hasNext()){
+ if(rowa==null)rowa=a.next();
+ if(rowb==null)rowb=b.next();
+ int cmp=compare.compare(rowa,rowb);
+ if(cmp<=0){
+ result.addRow(rowa);
+ rowa=null;
+ }else{
+ result.addRow(rowb);
+ rowb=null;
+ }
+ }
+ if(rowa!=null)result.addRow(rowa);
+ if(rowb!=null)result.addRow(rowb);
+ while(a.hasNext()){
+ result.addRow(a.next());
+ }
+ while(b.hasNext()){
+ result.addRow(b.next());
+ }
+ }
+
+ public void mergeSort(List<RowBuffer> buffers) throws IOException{
+ while(buffers.size()>2){
+ RowBuffer tmp=new RowBuffer(filename+"."+(bufnum++));
+ tmp.setCacheSize(allocBuffer());
+ // Grab two and sort to buf
+ RowBuffer a=buffers.remove(0);
+ RowBuffer b=buffers.remove(0);
+ mergeSort(tmp,a,b);
+ a.close();
+ freeBuffer(a);
+ b.close();
+ freeBuffer(b);
+ buffers.add(tmp);
+ }
+ if(buffers.size()==1){
+ result.close();
+ result=buffers.get(0);
+ result.prepare();
+ return;
+ }
+ if(buffers.size()==2){
+ RowBuffer a=buffers.get(0);
+ RowBuffer b=buffers.get(1);
+ mergeSort(result,a,b);
+ a.close();
+ freeBuffer(a);
+ b.close();
+ freeBuffer(b);
+ result.prepare();
+ return;
+ }
+ }
+
+ private int allocBuffer(){
+ if(BUFFERCACHE>=BUFFERLIMIT){
+ BUFFERCACHE-=BUFFERLIMIT;
+ return BUFFERLIMIT;
+ }
+ int tmp=BUFFERCACHE;
+ BUFFERCACHE=0;
+ return tmp;
+ }
+ private void freeBuffer(RowBuffer buf){
+ BUFFERCACHE+=buf.getCacheSize();
+ }
+
+ public void initialize(String filename,TupleStream source,List<SortRule> lst) throws IOException{
+ long prepart=System.currentTimeMillis();
+ this.filename=filename;
+ compare=new SortComparator(lst);
+ bufnum=0;
+ result=new RowBuffer(filename+".result");
+ result.setCacheSize(BUFFERLIMIT);
+ List<RowBuffer> buffers=new ArrayList<RowBuffer>();
+ int usage=0;
+
+ List<RowBuffer> prebuffers=new ArrayList<RowBuffer>();
+ List<Row> prebufferends=new ArrayList<Row>();
+ for(int i=0;i<PREBUFFERS;i++){
+ RowBuffer buf=new RowBuffer(filename+"."+(bufnum++));
+ buf.setCacheSize(allocBuffer());
+ prebuffers.add(buf);
+ }
+ int over=0;
+ RowBuffer overflow=new RowBuffer(filename+"."+(bufnum++));
+ overflow.setCacheSize(allocBuffer());
+ while(source.hasNext()){
+ Row rowa=source.next();
+ for(int i=0;(i<PREBUFFERS)&&(rowa!=null);i++){
+ if(i<prebufferends.size()){
+ Row rowb=prebufferends.get(i);
+ if(compare.compare(rowa,rowb)>0){
+ RowBuffer tmp=prebuffers.get(i);
+ tmp.addRow(rowa);
+ prebufferends.set(i,rowa);
+ rowa=null;
+ }
+ }else{
+ prebufferends.add(rowa);
+ RowBuffer tmp=prebuffers.get(i);
+ tmp.addRow(rowa);
+ rowa=null;
+ }
+ }
+ if(rowa!=null){
+ overflow.addRow(rowa);
+ over++;
+ }
+ }
+ for(int i=0;i<prebufferends.size();i++){
+ buffers.add(prebuffers.get(i));
+ }
+ long postpart=System.currentTimeMillis();
+ System.out.println("preprocess in "+(postpart-prepart)+" ms overflow:"+over);
+ source=overflow;
+ overflow.prepare();
+
+ List<Row> sortlst=new ArrayList<Row>();
+ while(source.hasNext()){
+ Row row=source.next();
+ if(usage+row.getSize()>MEMLIMIT){
+ RowBuffer buf=new RowBuffer(filename+"."+(bufnum++));
+ buf.setCacheSize(allocBuffer());
+ Collections.sort(sortlst,new SortComparator(lst));
+ for(int i=0;i<sortlst.size();i++){
+ buf.addRow(sortlst.get(i));
+ }
+ buffers.add(buf);
+ usage=0;
+ sortlst=new ArrayList<Row>();
+ }
+ sortlst.add(row);
+ usage+=row.getSize();
+ }
+ RowBuffer buf=new RowBuffer(filename+"."+(bufnum++));
+ buf.setCacheSize(allocBuffer());
+ Collections.sort(sortlst,new SortComparator(lst));
+ for(int i=0;i<sortlst.size();i++){
+ buf.addRow(sortlst.get(i));
+ }
+ buffers.add(buf);
+ mergeSort(buffers);
+ }
+ public boolean hasNext() throws IOException{
+ return result.hasNext();
+ }
+ public Row next() throws IOException{
+ return result.next();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+
+public abstract class QuickSort extends TupleStream{
+ public QuickSort(){
+
+ }
+ public void initialize(TupleStream source,List<SortRule> lst){
+
+ }
+ public abstract boolean hasNext();
+ public abstract Row next();
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+
+public abstract class RadixSort extends TupleStream{
+ public RadixSort(){
+
+ }
+ public void initialize(TupleStream source,List<SortRule> lst){
+
+ }
+ public abstract boolean hasNext();
+ public abstract Row next();
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import java.util.*;
+import java.io.*;
+import com.solidosystems.tuplesoup.core.*;
+
+public class RowBuffer extends TupleStream{
+ private int CACHESIZE=32768;
+ private int cacheusage=0;
+
+ private int mempointer=0;
+ private boolean diskused=false;
+
+ private List<Row> membuffer;
+ private String diskbuffer;
+ private DataOutputStream out;
+ private DataInputStream in;
+
+ private Row next=null;
+
+ public RowBuffer(String filename){
+ membuffer=new ArrayList<Row>();
+ diskbuffer=filename;
+ out=null;
+ in=null;
+ }
+
+ public void setCacheSize(int size){
+ CACHESIZE=size;
+ }
+ public int getCacheSize(){
+ return CACHESIZE;
+ }
+
+ public void addRow(Row row) throws IOException{
+ if(cacheusage+row.getSize()<=CACHESIZE){
+ membuffer.add(row);
+ cacheusage+=row.getSize();
+ }else{
+ cacheusage=CACHESIZE;
+ if(out==null)out=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(diskbuffer),2048));
+ row.writeToStream(out);
+ diskused=true;
+ }
+ }
+
+ public void prepare() throws IOException{
+ if(out!=null){
+ out.flush();
+ out.close();
+ }
+ mempointer=0;
+ if(diskused)in=new DataInputStream(new BufferedInputStream(new FileInputStream(diskbuffer),2048));
+ readNext();
+ }
+
+ public void close(){
+ try{
+ File ftest=new File(diskbuffer);
+ if(ftest.exists()){
+ if(out!=null)out.close();
+ if(in!=null)in.close();
+ ftest.delete();
+ }
+ }catch(Exception e){
+
+ }
+ }
+
+ private void readNext() throws IOException{
+ if(mempointer<membuffer.size()){
+ next=membuffer.get(mempointer++);
+ }else{
+ if(diskused){
+ try{
+ next=Row.readFromStream(in);
+ }catch(EOFException e){
+ next=null;
+ }
+ }else next=null;
+ }
+ }
+
+ public boolean hasNext() throws IOException{
+ if(next!=null)return true;
+ return false;
+ }
+
+ public Row next() throws IOException{
+ try{
+ if(next!=null){
+ Row tmp=next;
+ readNext();
+ return tmp;
+ }
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public abstract class Sort extends TupleStream{
+ public void initialize(String filename,TupleStream source,String key,int direction) throws IOException{
+ List<SortRule> lst=new ArrayList<SortRule>();
+ lst.add(new SortRule(key,direction));
+ initialize(filename,source,lst);
+ }
+ public void initialize(String filename,TupleStream source,String key,int direction,String key2,int direction2) throws IOException{
+ List<SortRule> lst=new ArrayList<SortRule>();
+ lst.add(new SortRule(key,direction));
+ lst.add(new SortRule(key2,direction2));
+ initialize(filename,source,lst);
+ }
+ public abstract void initialize(String filename,TupleStream source,List<SortRule> lst) throws IOException;
+ public abstract boolean hasNext() throws IOException;
+ public abstract Row next() throws IOException;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+
+public class SortComparator implements Comparator<Row>{
+ private List<SortRule> rules;
+
+ public SortComparator(List<SortRule> rules){
+ this.rules=rules;
+ }
+
+ private int compare(int rulenum,Row rowa,Row rowb){
+ if(rules.size()<=rulenum)return 0;
+ SortRule rule=rules.get(rulenum);
+ Value a=rowa.get(rule.getKey());
+ Value b=rowb.get(rule.getKey());
+ int result=a.compareTo(b);
+ // TODO: add direction switcher here
+ if(result==0){
+ rulenum++;
+ return compare(rulenum,rowa,rowb);
+ }else{
+ if(rule.getDirection()==SortRule.DESC){
+ if(result==-1){
+ result=1;
+ }else if(result==1)result=-1;
+ }
+ return result;
+ }
+ }
+
+ public int compare(Row rowa,Row rowb){
+ return compare(0,rowa,rowb);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+
+public class SortRule{
+ public static final int ASC=0;
+ public static final int DESC=1;
+
+ private String key;
+ private int direction;
+
+ public SortRule(String key, int direction){
+ this.key=key;
+ this.direction=direction;
+ }
+
+ public int getDirection(){
+ return direction;
+ }
+
+ public String getKey(){
+ return key;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.test;
+
+import java.util.*;
+
+public class BasicTest{
+ public List<String>errors=new ArrayList<String>();
+ private int lastlength=0;
+
+ public void err(String str){
+ while(lastlength<40){
+ System.out.print(" ");
+ lastlength++;
+ }
+ outbr(" ERR");
+ outbr(" ! "+str);
+ errors.add(str);
+ }
+
+ public void printErrorSummary(){
+ outbr("");
+ if(errors.size()==0){
+ outbr("All tests passed!");
+ }else if(errors.size()==1){
+ outbr("1 test failed!");
+ }else{
+ outbr(errors.size()+" tests failed!");
+ }
+ }
+
+ public static void die(String reason){
+ System.out.println("ERR");
+ System.out.println(" ! "+reason);
+ System.exit(0);
+ }
+
+ public void ok(){
+ while(lastlength<40){
+ System.out.print(" ");
+ lastlength++;
+ }
+ outbr(" OK");
+ }
+
+ public void outbr(String str){
+ outbr(0,str);
+ }
+
+ public void out(String str){
+ out(0,str);
+ }
+
+ public void outbr(int level, String str){
+ switch(level){
+ case 0:System.out.print("");
+ break;
+ case 1:System.out.print(" + ");
+ break;
+ case 2:System.out.print(" * ");
+ break;
+ case 3:System.out.print(" - ");
+ break;
+ case 4:System.out.print(" + ");
+ break;
+ }
+ System.out.println(str);
+ }
+
+ public void out(int level, String str){
+ lastlength=0;
+ switch(level){
+ case 0: System.out.print("");
+ break;
+ case 1: System.out.print(" + ");
+ lastlength+=3;
+ break;
+ case 2: System.out.print(" * ");
+ lastlength+=5;
+ break;
+ case 3: System.out.print(" - ");
+ lastlength+=7;
+ break;
+ }
+ System.out.print(str);
+ lastlength+=str.length();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.test;
+
+import com.solidosystems.tuplesoup.core.*;
+import com.solidosystems.tuplesoup.filter.*;
+
+import java.util.*;
+import java.io.*;
+import java.sql.*;
+
+
+public class ComparisonTest{
+ public int DATASET=50000;
+ public List<List<Long>>results;
+ public List<String>testnames;
+ public List<String>idlist;
+
+
+ public String generateId(int i){
+ return "user.number."+i+"@testdomain.lan";
+ }
+
+ public void testTupleSoup() throws Exception{
+ System.out.println(" + Running TupleSoup test");
+ Table tbl=new DualFileTable("CoreTestData",".");
+ tbl.deleteFiles();
+ tbl=new DualFileTable("CoreTestData",".",Table.PAGED);
+ //tbl.setIndexCacheSize(DATASET/10);
+ tbl.setIndexCacheSize(50000);
+ long pre=System.currentTimeMillis();
+
+ for(int i=0;i<DATASET;i++){
+ Row row=new Row(idlist.get(i));
+ row.put("name","Kasper J. Jeppesen");
+ row.put("age",(int)(Math.random()*60f)+20);
+ row.put("sex","male");
+ row.put("www","http://syntacticsirup.blogspot.com/");
+ row.put("tcreated",new java.util.Date());
+ tbl.addRow(row);
+ }
+ long post=System.currentTimeMillis();
+ long addtime=post-pre;
+ System.out.println(" - Add "+addtime+"ms");
+
+ pre=System.currentTimeMillis();
+ for(int i=0;i<DATASET/10;i++){
+ Row row=tbl.getRow(idlist.get((int)(Math.random()*DATASET)));
+ }
+ post=System.currentTimeMillis();
+ long fetchtime=post-pre;
+ System.out.println(" - Fetch "+fetchtime+"ms");
+
+ pre=System.currentTimeMillis();
+ for(int i=0;i<DATASET/10;i++){
+ Row row=tbl.getRow(idlist.get((int)(Math.random()*DATASET)));
+ row.put("age",row.getInt("age")+1);
+ tbl.updateRow(row);
+ }
+ post=System.currentTimeMillis();
+ long updatetime=post-pre;
+ System.out.println(" - Update "+updatetime+"ms");
+
+ // pre=System.currentTimeMillis();
+ // MergeSort msort=new MergeSort(8192000);
+ // msort.initialize("./tmpsort",tbl.getRows(),"age",SortRule.ASC);
+ // while(msort.hasNext()){
+ // Row row=msort.next();
+ // }
+ // post=System.currentTimeMillis();
+ // long sorttime=post-pre;
+ // System.out.println(" - Sort "+sorttime+"ms");
+
+ // addResults(addtime,fetchtime,updatetime,sorttime,0);
+ testnames.add("TupleSoup");
+ }
+
+ public void testGreedyTupleSoup() throws Exception{
+ System.out.println(" + Running Greedy TupleSoup test");
+ Table tbl=new DualFileTable("CoreTestData",".");
+ tbl.deleteFiles();
+ tbl=new DualFileTable("CoreTestData",".",Table.MEMORY);
+ tbl.setIndexCacheSize(0);
+ long pre=System.currentTimeMillis();
+
+ for(int i=0;i<DATASET;i++){
+ Row row=new Row(idlist.get(i));
+ row.put("name","Kasper J. Jeppesen");
+ row.put("age",(int)(Math.random()*60f)+20);
+ row.put("sex","male");
+ row.put("www","http://syntacticsirup.blogspot.com/");
+ row.put("tcreated",new java.util.Date());
+ tbl.addRow(row);
+ }
+ long post=System.currentTimeMillis();
+ long addtime=post-pre;
+ System.out.println(" - Add "+addtime+"ms");
+
+ pre=System.currentTimeMillis();
+ for(int i=0;i<DATASET/10;i++){
+ Row row=tbl.getRow(idlist.get((int)(Math.random()*DATASET)));
+ }
+ post=System.currentTimeMillis();
+ long fetchtime=post-pre;
+ System.out.println(" - Fetch "+fetchtime+"ms");
+
+ pre=System.currentTimeMillis();
+ for(int i=0;i<DATASET/10;i++){
+ Row row=tbl.getRow(idlist.get((int)(Math.random()*DATASET)));
+ row.put("age",row.getInt("age")+1);
+ tbl.updateRow(row);
+ }
+ post=System.currentTimeMillis();
+ long updatetime=post-pre;
+ System.out.println(" - Update "+updatetime+"ms");
+
+ pre=System.currentTimeMillis();
+ JavaSort msort=new JavaSort();
+ msort.initialize("./tmpsort",tbl.getRows(),"age",SortRule.ASC);
+ while(msort.hasNext()){
+ Row row=msort.next();
+ }
+ post=System.currentTimeMillis();
+ long sorttime=post-pre;
+ System.out.println(" - Sort "+sorttime+"ms");
+
+ addResults(addtime,fetchtime,updatetime,sorttime,0);
+ testnames.add("TupleSoup");
+ }
+
+ public void testPostgreSQL() throws Exception{
+ System.out.println(" + Running PostgreSQL test");
+ Class.forName("org.postgresql.Driver");
+ Connection con=DriverManager.getConnection("jdbc:postgresql:tupledb","tuple", "1234");
+ Statement st=con.createStatement();
+ try{
+ st.executeUpdate("DROP TABLE tbl_user");
+ }catch(Exception e){}
+ st.executeUpdate("CREATE TABLE tbl_user (id VARCHAR, name VARCHAR, age INT, sex VARCHAR, www VARCHAR, tcreated TIMESTAMP)");
+ st.executeUpdate("CREATE INDEX ndx_user ON tbl_user(id)");
+ st.executeUpdate("VACUUM FULL");
+ // con.setAutoCommit(false);
+ PreparedStatement pst=con.prepareStatement("INSERT INTO tbl_user (id,name,age,sex,www,tcreated) VALUES(?,?,?,?,?,?)");
+ long pre=System.currentTimeMillis();
+ for(int i=0;i<DATASET;i++){
+ // st.executeUpdate("INSERT INTO tbl_user (id,name,age,sex,www,tcreated) VALUES('"+generateId(i)+"','Kasper J. Jeppesen',"+((int)(Math.random()*60f)+20)+",'male','http://syntacticsirup.blogspot.com/',now())");
+ pst.setString(1,idlist.get(i));
+ pst.setString(2,"Kasper J. Jeppesen");
+ pst.setInt(3,((int)(Math.random()*60f)+20));
+ pst.setString(4,"male");
+ pst.setString(5,"http://syntacticsirup.blogspot.com/");
+ pst.setDate(6,new java.sql.Date(System.currentTimeMillis()));
+ pst.executeUpdate();
+ }
+ // con.commit();
+ long post=System.currentTimeMillis();
+ st.executeUpdate("ANALYZE");
+ long addtime=post-pre;
+ System.out.println(" - Add "+addtime+"ms");
+
+ pst=con.prepareStatement("SELECT name,age,sex,www,tcreated FROM tbl_user WHERE id=?");
+ pre=System.currentTimeMillis();
+ for(int i=0;i<DATASET/10;i++){
+ pst.setString(1,idlist.get((int)(Math.random()*DATASET)));
+ ResultSet rs=pst.executeQuery();
+ rs.next();
+ }
+ post=System.currentTimeMillis();
+ long fetchtime=post-pre;
+ System.out.println(" - Fetch "+fetchtime+"ms");
+
+ pst=con.prepareStatement("SELECT age FROM tbl_user WHERE id=?");
+ PreparedStatement pst2=con.prepareStatement("UPDATE tbl_user SET age=? WHERE id=?");
+ pre=System.currentTimeMillis();
+ for(int i=0;i<DATASET/10;i++){
+ pst.setString(1,idlist.get((int)(Math.random()*DATASET)));
+ ResultSet rs=pst.executeQuery();
+ rs.next();
+ pst2.setInt(1,rs.getInt(1)+1);
+ pst2.setString(2,idlist.get(i));
+ pst2.executeUpdate();
+ }
+ post=System.currentTimeMillis();
+ long updatetime=post-pre;
+ System.out.println(" - Update "+updatetime+"ms");
+
+ pre=System.currentTimeMillis();
+ ResultSet rs=st.executeQuery("SELECT id,name,age,sex,www,tcreated FROM tbl_user ORDER BY age");
+ while(rs.next()){
+ rs.getString(1);
+ }
+ post=System.currentTimeMillis();
+ long sorttime=post-pre;
+ System.out.println(" - Sort "+sorttime+"ms");
+
+
+ addResults(addtime,fetchtime,0,sorttime,0);
+ testnames.add("TupleSoup");
+ }
+
+ public void testMySQL() throws Exception{
+ System.out.println(" + Running MySQL test");
+ Class.forName("com.mysql.jdbc.Driver");
+ Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/tupledb","tuple", "1234");
+ Statement st=con.createStatement();
+ try{
+ st.executeUpdate("DROP TABLE tbl_user");
+ }catch(Exception e){}
+ st.executeUpdate("CREATE TABLE tbl_user (id VARCHAR(128), name VARCHAR(128), age INT, sex VARCHAR(16), www VARCHAR(128), tcreated TIMESTAMP)");
+ st.executeUpdate("CREATE INDEX ndx_user ON tbl_user(id)");
+ // st.executeUpdate("VACUUM FULL");
+ // con.setAutoCommit(false);
+ PreparedStatement pst=con.prepareStatement("INSERT INTO tbl_user (id,name,age,sex,www,tcreated) VALUES(?,?,?,?,?,?)");
+ long pre=System.currentTimeMillis();
+ for(int i=0;i<DATASET;i++){
+ // st.executeUpdate("INSERT INTO tbl_user (id,name,age,sex,www,tcreated) VALUES('"+generateId(i)+"','Kasper J. Jeppesen',"+((int)(Math.random()*60f)+20)+",'male','http://syntacticsirup.blogspot.com/',now())");
+ pst.setString(1,idlist.get(i));
+ pst.setString(2,"Kasper J. Jeppesen");
+ pst.setInt(3,((int)(Math.random()*60f)+20));
+ pst.setString(4,"male");
+ pst.setString(5,"http://syntacticsirup.blogspot.com/");
+ pst.setDate(6,new java.sql.Date(System.currentTimeMillis()));
+ pst.executeUpdate();
+ }
+ // con.commit();
+ long post=System.currentTimeMillis();
+ // st.executeUpdate("ANALYZE");
+ long addtime=post-pre;
+ System.out.println(" - Add "+addtime+"ms");
+
+ pst=con.prepareStatement("SELECT name,age,sex,www,tcreated FROM tbl_user WHERE id=?");
+ pre=System.currentTimeMillis();
+ for(int i=0;i<DATASET/10;i++){
+ pst.setString(1,idlist.get((int)(Math.random()*DATASET)));
+ ResultSet rs=pst.executeQuery();
+ rs.next();
+ }
+ post=System.currentTimeMillis();
+ long fetchtime=post-pre;
+ System.out.println(" - Fetch "+fetchtime+"ms");
+
+ pst=con.prepareStatement("SELECT age FROM tbl_user WHERE id=?");
+ PreparedStatement pst2=con.prepareStatement("UPDATE tbl_user SET age=? WHERE id=?");
+ pre=System.currentTimeMillis();
+ for(int i=0;i<DATASET/10;i++){
+ pst.setString(1,idlist.get((int)(Math.random()*DATASET)));
+ ResultSet rs=pst.executeQuery();
+ rs.next();
+ pst2.setInt(1,rs.getInt(1)+1);
+ pst2.setString(2,idlist.get(i));
+ pst2.executeUpdate();
+ }
+ post=System.currentTimeMillis();
+ long updatetime=post-pre;
+ System.out.println(" - Update "+updatetime+"ms");
+
+ pre=System.currentTimeMillis();
+ ResultSet rs=st.executeQuery("SELECT id,name,age,sex,www,tcreated FROM tbl_user ORDER BY age");
+ while(rs.next()){
+ rs.getString(1);
+ }
+ post=System.currentTimeMillis();
+ long sorttime=post-pre;
+ System.out.println(" - Sort "+sorttime+"ms");
+
+
+ addResults(addtime,fetchtime,0,sorttime,0);
+ testnames.add("TupleSoup");
+ }
+ public void addResults(long add,long fetch,long update,long sort,long sum){
+ List<Long> lst=new ArrayList<Long>();
+ lst.add(add);
+ lst.add(fetch);
+ lst.add(update);
+ lst.add(sort);
+ lst.add(sum);
+ results.add(lst);
+ }
+
+ public ComparisonTest(){
+ try{
+ for(int n=1;n<=20;n++){
+ DATASET=n*10000;
+ System.out.println("Running for "+DATASET);
+ idlist=new ArrayList<String>();
+ for(int i=0;i<DATASET;i++){
+ idlist.add(generateId(i));
+ }
+ Collections.shuffle(idlist);
+ results=new ArrayList<List<Long>>();
+ testnames=new ArrayList<String>();
+ // testGreedyTupleSoup();
+ testTupleSoup();
+ // testMySQL();
+ // testPostgreSQL();
+ }
+ // calcScores();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+
+ public void calcScores(){
+ System.out.println("Compared results");
+ }
+
+ public static void main(String[] args){
+ new ComparisonTest();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ package com.solidosystems.tuplesoup.test;
+
+ import com.solidosystems.tuplesoup.core.*;
+ import com.solidosystems.tuplesoup.filter.*;
+
+ import java.util.*;
+
+ public class CoreTest{
+ public static void main(String[] args){
+ try{
+ System.out.println("TupleSoup Core Data Test");
+ System.out.println(" + Preparing data");
+ Date dt=new Date();
+
+ Table tbl=new DualFileTable("CoreTestData",".");
+ tbl.deleteFiles();
+ tbl=new DualFileTable("CoreTestData",".");
+ Row row1=new Row("1");
+ row1.put("string","Hello World!");
+ row1.put("int",42);
+ row1.put("long",314l);
+ row1.put("float",3.14f);
+ row1.put("double",3.1415d);
+ row1.put("timestamp",dt);
+ row1.put("boolean",true);
+ tbl.addRow(row1);
+ Row row2=new Row("2");
+ row2.put("name","Kasper J");
+ row2.put("int",43);
+ tbl.addRow(row2);
+ Row row3=new Row("3");
+ row3.put("name","Kasper L");
+ row3.put("int",44);
+ tbl.addRow(row3);
+ Row row4=new Row("4");
+ row4.put("name","Christer");
+ row4.put("int",45);
+ tbl.addRow(row4);
+
+ System.out.print(" + Testing basic row storage ... ");
+ TupleStream it=tbl.getRows();
+ int cnt=0;
+ while(it.hasNext()){
+ it.next();
+ cnt++;
+ }
+ if(cnt!=4)die("Wrong number of rows in table after adding 4 rows");
+ Row tmp=tbl.getRow("1");
+ if(tmp==null)die("Could not fetch the first row");
+ if(!tmp.getString("string").equals("Hello World!"))die("String value incorrect after storage");
+ if(tmp.getInt("int")!=42)die("Int value incorrect after storage");
+ if(tmp.getLong("long")!=314l)die("Long value incorrect after storage");
+ if(tmp.getFloat("float")!=3.14f)die("Float value incorrect after storage");
+ if(tmp.getDouble("double")!=3.1415d)die("Double value incorrect after storage");
+ if(!tmp.getTimestamp("timestamp").equals(dt))die("Timestamp value incorrect after storage");
+ if(!tmp.getBoolean("boolean"))die("Boolean value incorrect after storage");
+ System.out.println("OK");
+
+ System.out.print(" + Testing bulk fetch order ... ");
+ List<String> lst=new ArrayList<String>();
+ lst.add("3");
+ lst.add("1");
+ lst.add("2");
+ lst.add("4");
+ lst.add("2");
+ it=tbl.getRows(lst);
+ tmp=it.next();
+ if(!tmp.getId().equals("3"))die("Elements returned in wrong order");
+ tmp=it.next();
+ if(!tmp.getId().equals("1"))die("Elements returned in wrong order");
+ tmp=it.next();
+ if(!tmp.getId().equals("2"))die("Elements returned in wrong order");
+ tmp=it.next();
+ if(!tmp.getId().equals("4"))die("Elements returned in wrong order");
+ System.out.println("OK");
+
+ System.out.print(" + Testing RowMatcher ... ");
+ RowMatcher m=new RowMatcher("name",RowMatcher.STARTSWITH,new Value("Kasper"));
+ it=tbl.getRows(m);
+ cnt=0;
+ while(it.hasNext()){
+ it.next();
+ cnt++;
+ }
+ if(cnt!=2)die("String based RowMatcher failed using STARTSWITH");
+ m=new RowMatcher("int",RowMatcher.GREATERTHAN,new Value(44));
+ it=tbl.getRows(m);
+ tmp=it.next();
+ if(!tmp.getId().equals("4"))die("Int based RowMatcher failed using GREATERTHAN");
+ // TODO: Add full test of all types and comparison types in RowMatcher
+ System.out.println("OK");
+
+ System.out.print(" + Testing row updates and deletes ... ");
+ tbl.deleteRow(row2);
+ row4.put("int",8192);
+ tbl.updateRow(row4);
+ it=tbl.getRows();
+ cnt=0;
+ while(it.hasNext()){
+ it.next();
+ cnt++;
+ }
+ if(cnt!=3)die("Wrong number of rows returned");
+ tmp=tbl.getRow("4");
+ if(tmp.getInt("int")!=8192)die("Wrong int value returned after update");
+
+ row1.put("longtext","Hello world again and again and again and again.....");
+ tbl.updateRow(row1);
+ tmp=tbl.getRow("1");
+ if(!tmp.getString("longtext").equals("Hello world again and again and again and again....."))die("Wrong string value returned after update");
+
+ System.out.println("OK");
+
+ System.out.print(" + Testing close and reopen ... ");
+ tbl.close();
+ tbl=new DualFileTable("CoreTestData",".");
+ it=tbl.getRows();
+ cnt=0;
+ while(it.hasNext()){
+ it.next();
+ cnt++;
+ }
+ if(cnt!=3)die("Wrong number of rows returned");
+ tmp=tbl.getRow("4");
+ if(tmp.getInt("int")!=8192)die("Wrong int value returned after close");
+ tmp=tbl.getRow("1");
+ if(!tmp.getString("longtext").equals("Hello world again and again and again and again....."))die("Wrong string value returned after update");
+
+ System.out.println("OK");
+
+ System.out.print(" + Testing large data sets ... ");
+ tbl.deleteFiles();
+ tbl=new DualFileTable("CoreTestData",".");
+ for(int i=0;i<50000;i++){
+ tmp=new Row(i+"_"+Math.random());
+ tmp.put("data1",Math.random());
+ tmp.put("one",1);
+ tbl.addRow(tmp);
+ }
+ tbl.close();
+ tbl=new DualFileTable("CoreTestData",".");
+ it=tbl.getRows();
+ cnt=0;
+ while(it.hasNext()){
+ it.next();
+ cnt++;
+ }
+ if(cnt!=50000)die("Wrong number of rows returned");
+ it=tbl.getRows();
+ cnt=0;
+ while(it.hasNext()){
+ tmp=it.next();
+ cnt+=tmp.getInt("one");
+ }
+ if(cnt!=50000)die("Wrong numeric data returned");
+
+ tmp=new Row("foo");
+ tmp.put("bar","baz");
+ tbl.addRow(tmp);
+ tbl.close();
+ tbl=new DualFileTable("CoreTestData",".");
+ tmp=tbl.getRow("foo");
+ if(!tmp.getString("bar").equals("baz"))die("Wrong string data returned");
+
+ it=tbl.getRows();
+ cnt=0;
+ while(it.hasNext()){
+ it.next();
+ cnt++;
+ }
+ if(cnt!=50001)die("Wrong number of rows returned");
+ System.out.println("OK");
+
+ System.exit(0);
+ tbl.close();
+ tbl.deleteFiles();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+ public static void die(String reason){
+ System.out.println("ERR");
+ System.out.println(" ! "+reason);
+ System.exit(0);
+ }
+ }
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ package com.solidosystems.tuplesoup.test;
+
+ import com.solidosystems.tuplesoup.core.*;
+ import com.solidosystems.tuplesoup.filter.*;
+
+ import java.util.*;
+ import java.io.*;
+
+
+public class ParallelPerformanceTest extends BasicTest implements Runnable{
+
+ long writetime;
+ long readtime;
+ long randomtime;
+
+ public ParallelPerformanceTest(){
+ String path="/Volumes/My Book/test/";
+ try{
+ int records=50000;
+ for(int i=1;i<11;i++){
+ outbr("Running Parallel DualFileTable Performance test");
+ outbr(1,i+" x "+(records/i)+" Large records");
+
+ outbr(2,"Memory index");
+ Table table=new DualFileTable("Performance-test",path,Table.MEMORY);
+ benchmark(table,i,(records/i));
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Flat index");
+ table=new DualFileTable("Performance-test",path,Table.FLAT);
+ benchmark(table,i,(records/i));
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Paged index");
+ table=new DualFileTable("Performance-test",path,Table.PAGED);
+ benchmark(table,i,(records/i));
+ table.close();
+ table.deleteFiles();
+
+ outbr("Running Parallel HashedTable Performance test");
+ outbr(1,i+" x "+(records/i)+" Large records");
+
+ outbr(2,"Memory index");
+ table=new HashedTable("Performance-test",path,Table.MEMORY);
+ benchmark(table,i,(records/i));
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Flat index");
+ table=new HashedTable("Performance-test",path,Table.FLAT);
+ benchmark(table,i,(records/i));
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Paged index");
+ table=new HashedTable("Performance-test",path,Table.PAGED);
+ benchmark(table,i,(records/i));
+ table.close();
+ table.deleteFiles();
+ }
+
+
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+ public static void main(String[] args){
+ new ParallelPerformanceTest();
+ }
+
+ public void benchmark(Table table,int threadcount, int records) throws Exception{
+ writetime=0;
+ readtime=0;
+ randomtime=0;
+ List<Thread> lst=new ArrayList<Thread>();
+ for(int i=0;i<threadcount;i++){
+ Thread thr=new Thread(new ParallelThread(this,table,i+"",records));
+ thr.start();
+ lst.add(thr);
+ }
+ for(int i=0;i<threadcount;i++){
+ lst.get(i).join();
+ }
+ outbr(3,"Write "+writetime+" ms");
+ outbr(3,"Read "+readtime+" ms");
+ outbr(3,"Random "+randomtime+" ms");
+ }
+
+ public void run(){
+
+ }
+
+ public long benchmarkLargeWrite(Table table,int records, String id) throws IOException{
+ long pre=System.currentTimeMillis();
+ for(int i=0;i<records;i++){
+ Row row=new Row(id+i);
+ row.put("key1","foobarbaz");
+ row.put("key2",123456);
+ row.put("key3",3.141592);
+ row.put("key4",true);
+ row.put("key5",new Value(new byte[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}));
+ table.addRow(row);
+ }
+ long post=System.currentTimeMillis();
+ return post-pre;
+ }
+ public long benchmarkLargeRead(Table table,int records, String id) throws IOException{
+ long pre=System.currentTimeMillis();
+ TupleStream stream=table.getRows();
+ while(stream.hasNext()){
+ stream.next();
+ }
+ long post=System.currentTimeMillis();
+ return post-pre;
+ }
+ public long benchmarkLargeRandomRead(Table table,int records, String id) throws IOException{
+ long pre=System.currentTimeMillis();
+ for(int i=0;i<records;i++){
+ Row row=table.getRow(id+(int)(Math.random()*records));
+ }
+ long post=System.currentTimeMillis();
+ return post-pre;
+ }
+
+ public void printStats(Hashtable<String,Long> hash){
+ Set<String> keys=hash.keySet();
+ Iterator<String> it=keys.iterator();
+ while(it.hasNext()){
+ String key=it.next();
+ outbr(4,key+" "+hash.get(key));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ package com.solidosystems.tuplesoup.test;
+
+ import com.solidosystems.tuplesoup.core.*;
+ import com.solidosystems.tuplesoup.filter.*;
+
+ import java.util.*;
+ import java.io.*;
+
+
+public class ParallelThread implements Runnable{
+ String id;
+ int records;
+ ParallelPerformanceTest app;
+ Table table;
+
+ public ParallelThread(ParallelPerformanceTest app,Table table,String id,int records){
+ this.id=id;
+ this.records=records;
+ this.app=app;
+ this.table=table;
+ }
+
+ public void run(){
+ try{
+ long time=app.benchmarkLargeWrite(table,records,id);
+ synchronized(app){
+ app.writetime+=time;
+ }
+ time=app.benchmarkLargeRead(table,records,id);
+ synchronized(app){
+ app.readtime+=time;
+ }
+ time=app.benchmarkLargeRandomRead(table,records,id);
+ synchronized(app){
+ app.randomtime+=time;
+ }
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ package com.solidosystems.tuplesoup.test;
+
+ import com.solidosystems.tuplesoup.core.*;
+ import com.solidosystems.tuplesoup.filter.*;
+
+ import java.util.*;
+ import java.io.*;
+
+
+public class PerformanceTest extends BasicTest{
+ public PerformanceTest(){
+ try{
+ outbr("Running DualFileTable Performance test");
+ outbr(1,"10000 small records");
+
+ outbr(2,"Memory index");
+ Table table=new DualFileTable("Performance-test","./",Table.MEMORY);
+ benchmarkSmall(table,10000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Flat index");
+ table=new DualFileTable("Performance-test","./",Table.FLAT);
+ benchmarkSmall(table,10000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Paged index");
+ table=new DualFileTable("Performance-test","./",Table.PAGED);
+ benchmarkSmall(table,10000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(1,"20000 large records");
+
+ outbr(2,"Memory index");
+ table=new DualFileTable("Performance-test","./",Table.MEMORY);
+ benchmarkLarge(table,20000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Flat index");
+ table=new DualFileTable("Performance-test","./",Table.FLAT);
+ benchmarkLarge(table,20000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Paged index");
+ table=new DualFileTable("Performance-test","./",Table.PAGED);
+ benchmarkLarge(table,20000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(1,"30000 large records");
+
+ outbr(2,"Memory index");
+ table=new DualFileTable("Performance-test","./",Table.MEMORY);
+ benchmarkLarge(table,30000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Flat index");
+ table=new DualFileTable("Performance-test","./",Table.FLAT);
+ benchmarkLarge(table,30000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Paged index");
+ table=new DualFileTable("Performance-test","./",Table.PAGED);
+ benchmarkLarge(table,30000);
+ table.close();
+ table.deleteFiles();
+
+ outbr("Running HashedTable Performance test");
+ outbr(1,"10000 small records");
+
+ outbr(2,"Memory index");
+ table=new HashedTable("Performance-test","./",Table.MEMORY);
+ benchmarkSmall(table,10000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Flat index");
+ table=new HashedTable("Performance-test","./",Table.FLAT);
+ benchmarkSmall(table,10000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Paged index");
+ table=new HashedTable("Performance-test","./",Table.PAGED);
+ benchmarkSmall(table,10000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(1,"20000 large records");
+
+ outbr(2,"Memory index");
+ table=new HashedTable("Performance-test","./",Table.MEMORY);
+ benchmarkLarge(table,20000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Flat index");
+ table=new HashedTable("Performance-test","./",Table.FLAT);
+ benchmarkLarge(table,20000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Paged index");
+ table=new HashedTable("Performance-test","./",Table.PAGED);
+ benchmarkLarge(table,20000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(1,"30000 large records");
+
+ outbr(2,"Memory index");
+ table=new HashedTable("Performance-test","./",Table.MEMORY);
+ benchmarkLarge(table,30000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Flat index");
+ table=new HashedTable("Performance-test","./",Table.FLAT);
+ benchmarkLarge(table,30000);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Paged index");
+ table=new HashedTable("Performance-test","./",Table.PAGED);
+ benchmarkLarge(table,30000);
+ table.close();
+ table.deleteFiles();
+
+
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+ public static void main(String[] args){
+ new PerformanceTest();
+ }
+
+ public void benchmarkSmall(Table table,int records) throws IOException{
+ long pre=System.currentTimeMillis();
+ for(int i=0;i<records;i++){
+ Row row=new Row(""+i);
+ row.put("key1","foo");
+ table.addRow(row);
+ }
+ long post=System.currentTimeMillis();
+ outbr(3,"Write "+(post-pre)+" ms");
+ pre=System.currentTimeMillis();
+ TupleStream stream=table.getRows();
+ while(stream.hasNext()){
+ stream.next();
+ }
+ post=System.currentTimeMillis();
+ outbr(3,"Read "+(post-pre)+" ms");
+ pre=System.currentTimeMillis();
+ for(int i=0;i<records;i++){
+ Row row=table.getRow(""+(int)(Math.random()*records));
+ }
+ post=System.currentTimeMillis();
+ outbr(3,"Random read "+(post-pre)+" ms");
+
+ // printStats(table.readStatistics());
+ }
+
+ public void benchmarkLarge(Table table,int records) throws IOException{
+ long pre=System.currentTimeMillis();
+ for(int i=0;i<records;i++){
+ Row row=new Row(""+i);
+ row.put("key1","foobarbaz");
+ row.put("key2",123456);
+ row.put("key3",3.141592);
+ row.put("key4",true);
+ row.put("key5",new Value(new byte[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}));
+ table.addRow(row);
+ }
+ long post=System.currentTimeMillis();
+ outbr(3,"Write "+(post-pre)+" ms");
+ pre=System.currentTimeMillis();
+ TupleStream stream=table.getRows();
+ while(stream.hasNext()){
+ stream.next();
+ }
+ post=System.currentTimeMillis();
+ outbr(3,"Read "+(post-pre)+" ms");
+ pre=System.currentTimeMillis();
+ for(int i=0;i<records;i++){
+ Row row=table.getRow(""+(int)(Math.random()*records));
+ }
+ post=System.currentTimeMillis();
+ outbr(3,"Random read "+(post-pre)+" ms");
+
+ // printStats(table.readStatistics());
+ }
+
+ public void printStats(Hashtable<String,Long> hash){
+ Set<String> keys=hash.keySet();
+ Iterator<String> it=keys.iterator();
+ while(it.hasNext()){
+ String key=it.next();
+ outbr(4,key+" "+hash.get(key));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.test;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class RowTest extends BasicTest{
+ public RowTest(){
+
+ }
+ public void runTest(){
+ outbr("Running core Row functionality test");
+ outbr(1,"Constructor initializers");
+
+ out(2,"String");
+ Row row=new Row("FooBarBaz");
+ if(!row.getId().equals("FooBarBaz")){
+ err("Id value not correct");
+ }else if(row.getKeyCount()!=0){
+ err("Key count not correct");
+ }else ok();
+
+ outbr(1,"Setting and getting values");
+
+ out(2,"Setting values");
+ row.put("key1",new Value(3.1415f));
+ row.put("key2","FooBar");
+ row.put("key3",1234);
+ row.put("key4",5123456789l);
+ row.put("key5",3.1415f);
+ row.put("key6",3.141592653689793284626433d);
+ row.put("key7",true);
+ row.put("key8",new java.util.Date(5));
+ if(row.getKeyCount()!=8){
+ err("Key count not correct");
+ }else ok();
+
+ out(2,"Getting values");
+ Value val1=new Value("FooBar");
+ Value val2=new Value(1234);
+ Value val3=new Value(5123456789l);
+ Value val4=new Value(3.1415f);
+ Value val5=new Value(3.141592653689793284626433d);
+ Value val6=new Value(true);
+ Value val7=new Value(new java.util.Date(5));
+ if(!row.get("key1").equals(val4)){
+ err("Wrong Value value returned");
+ }else if(!row.get("key2").equals(val1)){
+ err("Wrong Value value returned");
+ }else if(!row.get("key3").equals(val2)){
+ err("Wrong Value value returned");
+ }else if(!row.get("key4").equals(val3)){
+ err("Wrong Value value returned");
+ }else if(!row.get("key5").equals(val4)){
+ err("Wrong Value value returned");
+ }else if(!row.get("key6").equals(val5)){
+ err("Wrong Value value returned");
+ }else if(!row.get("key7").equals(val6)){
+ err("Wrong Value value returned");
+ }else if(row.getKeyCount()!=8){
+ err("Wrong key count returned");
+ }else if(row.getFloat("key1")!=3.1415f){
+ err("Wrong value returned from getFloat");
+ }else if(!row.getString("key2").equals("FooBar")){
+ err("Wrong value returned from getString");
+ }else if(row.getInt("key3")!=1234){
+ err("Wrong value returned from getInt");
+ }else if(row.getLong("key4")!=5123456789l){
+ err("Wrong value returned from getLong");
+ }else if(row.getFloat("key5")!=3.1415f){
+ err("Wrong value returned from getFloat");
+ }else if(row.getDouble("key6")!=3.141592653689793284626433d){
+ err("Wrong value returned from getDouble");
+ }else if(!row.getBoolean("key7")){
+ err("Wrong value returned from getBoolean");
+ }else if(row.getTimestamp("key8").getTime()!=5){
+ err("Wrong value returned from getTimestamp");
+ }else ok();
+
+ outbr(1,"Stream reading and writing");
+ try{
+ out(2,"Writing to stream");
+ ByteArrayOutputStream bout=new ByteArrayOutputStream();
+ DataOutputStream dout=new DataOutputStream(bout);
+
+ row.writeToStream(dout);
+ row.put("key9","ExtraBonusValue");
+ row.writeToStream(dout);
+ dout.flush();
+ ok();
+
+ out(2,"Reading from stream");
+ byte[] buf=bout.toByteArray();
+ DataInputStream din=new DataInputStream(new ByteArrayInputStream(buf));
+ row=Row.readFromStream(din);
+ if(row.getKeyCount()!=8){
+ err("Wrong key count returned");
+ }else if(row.getFloat("key1")!=3.1415f){
+ err("Wrong value returned from getFloat");
+ }else if(!row.getString("key2").equals("FooBar")){
+ err("Wrong value returned from getString");
+ }else if(row.getInt("key3")!=1234){
+ err("Wrong value returned from getInt");
+ }else if(row.getLong("key4")!=5123456789l){
+ err("Wrong value returned from getLong");
+ }else if(row.getFloat("key5")!=3.1415f){
+ err("Wrong value returned from getFloat");
+ }else if(row.getDouble("key6")!=3.141592653689793284626433d){
+ err("Wrong value returned from getDouble");
+ }else if(!row.getBoolean("key7")){
+ err("Wrong value returned from getBoolean");
+ }else if(row.getTimestamp("key8").getTime()!=5){
+ err("Wrong value returned from getTimestamp");
+ }else{
+ row=Row.readFromStream(din);
+ if(!row.getString("key9").equals("ExtraBonusValue")){
+ err("Wrong value returned on second row written");
+ }else ok();
+ }
+
+ }catch(Exception e){
+ err("Exception occured "+e);
+ }
+
+ printErrorSummary();
+ }
+ public static void main(String args[]){
+ RowTest rowt=new RowTest();
+ rowt.runTest();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.test;
+
+import com.solidosystems.tuplesoup.core.*;
+import com.solidosystems.tuplesoup.filter.*;
+import java.util.*;
+import java.io.*;
+
+public class SortTest{
+ public static void main(String[] args){
+ String[] first_names={"Adolf","Anders","Bo","Christer","Daniel","Erik","Frederik","Georg","Hans","Hans-Christian","Ingolf","Jens","Kasper","Lars","Mads","Niels","Ole","Per","Rasmus","Søren","Tue","Ulrik"};
+ String[] last_names={"Jeppesen","Andersen","Hansen","Nielsen","Langer","Sørensen","Shore","Crane","Saustrup"};
+ String[] domains={"email.lan","mymail.lan","lukewarmmail.lan","lessthanfree.lan","devnull.lan"};
+ try{
+ System.out.println("TupleSoup Performance Test");
+ System.out.println(" + Simple user data");
+ Table tbl=new DualFileTable("CoreTestData",".");
+ tbl.deleteFiles();
+ tbl=new DualFileTable("CoreTestData",".",Table.PAGED);
+ tbl.setIndexCacheSize(10000);
+ int rows=100000;
+ System.out.print(" - Adding "+rows+" tuples in random order ... ");
+ long pre=System.currentTimeMillis();
+ long size=0;
+ List<String>flst=new ArrayList<String>();
+ for(int i=0;i<rows;i++){
+ flst.add(""+i);
+ }
+ Collections.shuffle(flst);
+
+ for(int i=0;i<rows;i++){
+ Row tmp=new Row(flst.get(i));
+ // Row tmp=new Row(""+i);
+ tmp.put("name",first_names[(int)(Math.random()*first_names.length)]+" "+last_names[(int)(Math.random()*last_names.length)]);
+ tmp.put("age",(float)(Math.random()*60f)+20f);
+ // tmp.put("age",i);
+ tmp.put("sex","male");
+ tmp.put("zipcode",(int)(Math.random()*8200f)+1000);
+ tmp.put("email",first_names[(int)(Math.random()*first_names.length)].toLowerCase()+"@"+domains[(int)(Math.random()*domains.length)]);
+ tbl.addRow(tmp);
+ size+=tmp.getSize();
+ }
+ long post=System.currentTimeMillis();
+ System.out.println((post-pre)+"ms avg:"+((post-pre)/((float)rows))+"ms "+(size/1024)+"kb "+((size/1024)/((post-pre)/1000f))+"kb/s "+(size/rows)+"b/row");
+
+ size=0;
+ System.out.print(" - Adding "+rows+" tuples to RowBuffer ... ");
+ RowBuffer buf=new RowBuffer("./foobarbaz");
+ buf.setCacheSize(1024000);
+ pre=System.currentTimeMillis();
+ for(int i=0;i<rows;i++){
+ Row tmp=new Row(flst.get(i));
+ // Row tmp=new Row(""+i);
+ tmp.put("name",first_names[(int)(Math.random()*first_names.length)]+" "+last_names[(int)(Math.random()*last_names.length)]);
+ tmp.put("age",(float)(Math.random()*60f)+20f);
+ // tmp.put("age",i);
+ tmp.put("sex","male");
+ tmp.put("zipcode",(int)(Math.random()*8200f)+1000);
+ tmp.put("email",first_names[(int)(Math.random()*first_names.length)].toLowerCase()+"@"+domains[(int)(Math.random()*domains.length)]);
+ buf.addRow(tmp);
+ size+=tmp.getSize();
+ }
+ post=System.currentTimeMillis();
+ System.out.println((post-pre)+"ms avg:"+((post-pre)/((float)rows))+"ms "+(size/1024)+"kb "+((size/1024)/((post-pre)/1000f))+"kb/s "+(size/rows)+"b/row");
+
+
+
+ System.out.print(" - Fetching all rows from RowBuffer sequentially in bulk ... ");
+ pre=System.currentTimeMillis();
+ buf.prepare();
+ while(buf.hasNext()){
+ Row r2=buf.next();
+ }
+ post=System.currentTimeMillis();
+ System.out.println((post-pre)+"ms "+((post-pre)/(float)rows)+"ms/row");
+
+
+ System.out.print(" - Fetching all rows from table sequentially in bulk ... ");
+ pre=System.currentTimeMillis();
+ TupleStream it=tbl.getRows();
+ while(it.hasNext()){
+ Row r2=it.next();
+ }
+ post=System.currentTimeMillis();
+ System.out.println((post-pre)+"ms "+((post-pre)/(float)rows)+"ms/row");
+ long fetchtime=post-pre;
+
+ System.out.print(" - Fetching all rows sorted in bulk (JavaSort) ... ");
+ pre=System.currentTimeMillis();
+ JavaSort sort=new JavaSort();
+ sort.initialize("./tmpsort",tbl.getRows(),"age",SortRule.ASC);
+ while(sort.hasNext()){
+ Row r2=sort.next();
+ // System.out.println(r2.getString("age"));
+ }
+ post=System.currentTimeMillis();
+ System.out.println(((post-pre)-fetchtime)+"ms "+(((post-pre)-fetchtime)/(float)rows)+"ms/row");
+
+ System.out.print(" - Fetching all rows sorted in bulk (MergeSort 4mb cache) ... ");
+ pre=System.currentTimeMillis();
+ MergeSort msort=new MergeSort(4096000);
+ msort.initialize("./tmpsort",tbl.getRows(),"age",SortRule.ASC);
+ while(msort.hasNext()){
+ Row r2=msort.next();
+ }
+ post=System.currentTimeMillis();
+ System.out.println(((post-pre)-fetchtime)+"ms "+(((post-pre)-fetchtime)/(float)rows)+"ms/row ");
+
+ System.out.print(" - Fetching all rows sorted in bulk (MergeSort 2mb cache) ... ");
+ pre=System.currentTimeMillis();
+ msort=new MergeSort(2048000);
+ msort.initialize("./tmpsort",tbl.getRows(),"age",SortRule.ASC);
+ while(msort.hasNext()){
+ Row r2=msort.next();
+ // System.out.println(r2.getString("age"));
+ }
+ post=System.currentTimeMillis();
+ System.out.println(((post-pre)-fetchtime)+"ms "+(((post-pre)-fetchtime)/(float)rows)+"ms/row ");
+
+ System.out.print(" - Fetching all rows sorted in bulk (MergeSort 1mb cache) ... ");
+ pre=System.currentTimeMillis();
+ msort=new MergeSort(1024000);
+ msort.initialize("./tmpsort",tbl.getRows(),"age",SortRule.ASC);
+ while(msort.hasNext()){
+ Row r2=msort.next();
+ // System.out.println(r2.getString("age"));
+ }
+ post=System.currentTimeMillis();
+ System.out.println(((post-pre)-fetchtime)+"ms "+(((post-pre)-fetchtime)/(float)rows)+"ms/row ");
+
+
+ System.out.print(" - Fetching all rows sorted in bulk (MergeSort 512kb cache) ... ");
+ pre=System.currentTimeMillis();
+ msort=new MergeSort(512000);
+ msort.initialize("./tmpsort",tbl.getRows(),"age",SortRule.ASC);
+ while(msort.hasNext()){
+ Row r2=msort.next();
+ // System.out.println(r2.getString("age"));
+ }
+ post=System.currentTimeMillis();
+ System.out.println(((post-pre)-fetchtime)+"ms "+(((post-pre)-fetchtime)/(float)rows)+"ms/row");
+
+
+ tbl.deleteFiles();
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.test;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class TableTest extends BasicTest{
+ public TableTest(){
+
+ }
+
+ public void runTest(){
+ outbr("Running core DualFileTable functionality test");
+ try{
+ outbr(1,"Creating new table");
+
+ out(2,"Default index");
+ Table table=new DualFileTable("TableTest-test","./");
+ if(!table.getTitle().equals("TableTest-test")){
+ err("Wrong table title returned");
+ }else if(!table.getLocation().equals("./")){
+ err("Wrong table location returned");
+ }else{
+ table.close();
+ table.deleteFiles();
+ ok();
+ }
+ out(2,"Memory index");
+ table=new DualFileTable("TableTest-test","./",Table.MEMORY);
+ table.close();
+ table.deleteFiles();
+ ok();
+
+ out(2,"Flat index");
+ table=new DualFileTable("TableTest-test","./",Table.FLAT);
+ table.close();
+ table.deleteFiles();
+ ok();
+
+ out(2,"Paged index");
+ table=new DualFileTable("TableTest-test","./",Table.PAGED);
+ table.close();
+ table.deleteFiles();
+ ok();
+
+ outbr(1,"Testing add, update, delete and read of data");
+
+
+
+ outbr(2,"Memory index");
+ table=new DualFileTable("TableTest-test","./",Table.MEMORY);
+ testIndex(table);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Flat index");
+ table=new DualFileTable("TableTest-test","./",Table.FLAT);
+ testIndex(table);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Paged index");
+ table=new DualFileTable("TableTest-test","./",Table.PAGED);
+ testIndex(table);
+ table.close();
+ table.deleteFiles();
+
+ outbr(1,"Close and reopen tables after bulk operations");
+ out(2,"Memory index");
+ table=new DualFileTable("TableTest-test","./",Table.MEMORY);
+ bulkOperate(table);
+ table.close();
+ table=new DualFileTable("TableTest-test","./",Table.MEMORY);
+ boolean bad=false;
+ TupleStream stream=table.getRows();
+ int count=0;
+ while(stream.hasNext()){
+ Row row=stream.next();
+ if(row.getDouble("key3")!=3.1415)bad=true;
+ count++;
+ }
+ if(bad){
+ err("Bad values returned after reopening table");
+ }else if(count!=5000){
+ err("Wrong number of rows returned after reopening table");
+ }else ok();
+ table.close();
+ table.deleteFiles();
+
+ out(2,"Flat index");
+ table=new DualFileTable("TableTest-test","./",Table.FLAT);
+ bulkOperate(table);
+ table.close();
+ table=new DualFileTable("TableTest-test","./",Table.FLAT);
+ bad=false;
+ stream=table.getRows();
+ count=0;
+ while(stream.hasNext()){
+ Row row=stream.next();
+ if(row.getDouble("key3")!=3.1415)bad=true;
+ count++;
+ }
+ if(bad){
+ err("Bad values returned after reopening table");
+ }else if(count!=5000){
+ err("Wrong number of rows returned after reopening table");
+ }else ok();
+ table.close();
+ table.deleteFiles();
+
+ out(2,"Paged index");
+ table=new DualFileTable("TableTest-test","./",Table.PAGED);
+ bulkOperate(table);
+ table.close();
+ table=new DualFileTable("TableTest-test","./",Table.PAGED);
+ bad=false;
+ stream=table.getRows();
+ count=0;
+ while(stream.hasNext()){
+ Row row=stream.next();
+ if(row.getDouble("key3")!=3.1415)bad=true;
+ count++;
+ }
+ if(bad){
+ err("Bad values returned after reopening table");
+ }else if(count!=5000){
+ err("Wrong number of rows returned after reopening table");
+ }else ok();
+ table.close();
+ table.deleteFiles();
+
+ }catch(Exception e){
+ err("Exception occured while testing "+e);
+ }
+ outbr("Running core HashedTable functionality test");
+ try{
+ outbr(1,"Creating new table");
+
+ out(2,"Default index");
+ Table table=new HashedTable("TableTest-test","./");
+ if(!table.getTitle().equals("TableTest-test")){
+ err("Wrong table title returned");
+ }else if(!table.getLocation().equals("./")){
+ err("Wrong table location returned");
+ }else{
+ table.close();
+ table.deleteFiles();
+ ok();
+ }
+ out(2,"Memory index");
+ table=new HashedTable("TableTest-test","./",Table.MEMORY);
+ table.close();
+ table.deleteFiles();
+ ok();
+
+ out(2,"Flat index");
+ table=new HashedTable("TableTest-test","./",Table.FLAT);
+ table.close();
+ table.deleteFiles();
+ ok();
+
+ out(2,"Paged index");
+ table=new HashedTable("TableTest-test","./",Table.PAGED);
+ table.close();
+ table.deleteFiles();
+ ok();
+
+ outbr(1,"Testing add, update, delete and read of data");
+
+
+
+ outbr(2,"Memory index");
+ table=new HashedTable("TableTest-test","./",Table.MEMORY);
+ testIndex(table);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Flat index");
+ table=new HashedTable("TableTest-test","./",Table.FLAT);
+ testIndex(table);
+ table.close();
+ table.deleteFiles();
+
+ outbr(2,"Paged index");
+ table=new HashedTable("TableTest-test","./",Table.PAGED);
+ testIndex(table);
+ table.close();
+ table.deleteFiles();
+
+ outbr(1,"Close and reopen tables after bulk operations");
+ out(2,"Memory index");
+ table=new HashedTable("TableTest-test","./",Table.MEMORY);
+ bulkOperate(table);
+ table.close();
+ table=new HashedTable("TableTest-test","./",Table.MEMORY);
+ boolean bad=false;
+ TupleStream stream=table.getRows();
+ int count=0;
+ while(stream.hasNext()){
+ Row row=stream.next();
+ if(row.getDouble("key3")!=3.1415)bad=true;
+ count++;
+ }
+ if(bad){
+ err("Bad values returned after reopening table");
+ }else if(count!=5000){
+ err("Wrong number of rows returned after reopening table");
+ }else ok();
+ table.close();
+ table.deleteFiles();
+
+ out(2,"Flat index");
+ table=new HashedTable("TableTest-test","./",Table.FLAT);
+ bulkOperate(table);
+ table.close();
+ table=new HashedTable("TableTest-test","./",Table.FLAT);
+ bad=false;
+ stream=table.getRows();
+ count=0;
+ while(stream.hasNext()){
+ Row row=stream.next();
+ if(row.getDouble("key3")!=3.1415)bad=true;
+ count++;
+ }
+ if(bad){
+ err("Bad values returned after reopening table");
+ }else if(count!=5000){
+ err("Wrong number of rows returned after reopening table");
+ }else ok();
+ table.close();
+ table.deleteFiles();
+
+ out(2,"Paged index");
+ table=new HashedTable("TableTest-test","./",Table.PAGED);
+ bulkOperate(table);
+ table.close();
+ table=new HashedTable("TableTest-test","./",Table.PAGED);
+ bad=false;
+ stream=table.getRows();
+ count=0;
+ while(stream.hasNext()){
+ Row row=stream.next();
+ if(row.getDouble("key3")!=3.1415)bad=true;
+ count++;
+ }
+ if(bad){
+ err("Bad values returned after reopening table");
+ }else if(count!=5000){
+ err("Wrong number of rows returned after reopening table");
+ }else ok();
+ table.close();
+ table.deleteFiles();
+
+ }catch(Exception e){
+ err("Exception occured while testing "+e);
+ }
+ }
+
+ public void bulkOperate(Table table) throws IOException{
+ for(int i=0;i<10000;i++){
+ Row row=new Row(""+i);
+ row.put("key1","foo");
+ row.put("key2",i);
+ table.addRow(row);
+ }
+ for(int i=0;i<5000;i++){
+ Row row=table.getRow(""+i);
+ table.deleteRow(row);
+ }
+ for(int i=5000;i<10000;i++){
+ Row row=table.getRow(""+i);
+ row.put("key3",3.1415);
+ row.put("key2",row.getInt("key2")+1);
+ table.updateRow(row);
+ }
+ }
+
+ public void testIndex(Table table) throws IOException{
+ Row row1=new Row("1");
+ row1.put("key1",1);
+ row1.put("key2","foo");
+
+ Row row2=new Row("2");
+ row2.put("key1",2);
+ row2.put("key2","foo");
+
+ Row row3=new Row("3");
+ row3.put("key1",3);
+ row3.put("key2","foo");
+
+ Row row4=new Row("4");
+ row4.put("key1",4);
+ row4.put("key2","foo");
+
+ Row row5=new Row("5");
+ row5.put("key1",5);
+ row5.put("key2","foo");
+
+ out(3,"Adding rows");
+ table.addRow(row1);
+ table.addRow(row2);
+ table.addRow(row3);
+ table.addRow(row4);
+ table.addRow(row5);
+ ok();
+
+ out(3,"Reading rows");
+ TupleStream stream=table.getRows();
+ int count=0;
+ while(stream.hasNext()){
+ Row tmp=stream.next();
+ count++;
+ }
+ if(count!=5){
+ err("Wrong number of rows returned");
+ }else{
+ Row tmp=table.getRow("1");
+ if(tmp==null){
+ err("Row not found");
+ }else{
+ if(tmp.getInt("key1")!=1){
+ err("Wrong value in returned row");
+ }else{
+ tmp=table.getRow("5");
+ if(tmp==null){
+ err("Row not found");
+ }else{
+ if(tmp.getInt("key1")!=5){
+ err("Wrong value in returned row");
+ }else{
+ ok();
+ }
+ }
+ }
+ }
+ }
+
+ out(3,"Updating rows");
+ Row tmp=table.getRow("1");
+ tmp.put("key3","bar");
+ table.updateRow(tmp);
+ tmp=table.getRow("1");
+ if(!tmp.getString("key3").equals("bar")){
+ err("Wrong value returned after update");
+ }else ok();
+
+ out(3,"Deleting rows");
+ tmp=table.getRow("1");
+ table.deleteRow(tmp);
+ stream=table.getRows();
+ count=0;
+ while(stream.hasNext()){
+ tmp=stream.next();
+ count++;
+ }
+ if(count!=4){
+ err("Wrong number of rows returned");
+ }else ok();
+ }
+
+ public static void main(String args[]){
+ TableTest tablet=new TableTest();
+ tablet.runTest();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.solidosystems.tuplesoup.test;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class ValueTest extends BasicTest{
+ private Value val=null;
+
+ public ValueTest(){
+ }
+ public void runTest(){
+ outbr("Running core Value functionality test");
+
+ outbr(1,"Constructor initializers");
+
+ out(2,"String");
+ val=new Value("FooBar");
+ if(val.getType()!=Value.STRING){
+ err("Numerical type incorrect");
+ }else{
+ if(!val.getTypeName().equals("string")){
+ err("Type name incorrect");
+ }else{
+ if(!val.getString().equals("FooBar")){
+ err("Returned value incorrect");
+ }else ok();
+ }
+ }
+
+ out(2,"Timestamp");
+ val=new Value(new java.util.Date(5));
+ if(val.getType()!=Value.TIMESTAMP){
+ err("Numerical type incorrect");
+ }else{
+ if(!val.getTypeName().equals("timestamp")){
+ err("Type name incorrect");
+ }else{
+ if(val.getTimestamp().getTime()!=5){
+ err("Returned value incorrect");
+ }else ok();
+ }
+ }
+
+ out(2,"Null");
+ val=new Value();
+ if(val.getType()!=Value.NULL){
+ err("Numerical type incorrect");
+ }else{
+ if(!val.getTypeName().equals("null")){
+ err("Type name incorrect");
+ }else ok();
+ }
+
+ out(2,"Int");
+ val=new Value(123456789);
+ if(val.getType()!=Value.INT){
+ err("Numerical type incorrect");
+ }else{
+ if(!val.getTypeName().equals("int")){
+ err("Type name incorrect");
+ }else{
+ if(val.getInt()!=123456789){
+ err("Returned value incorrect");
+ }else ok();
+ }
+ }
+
+ out(2,"Long");
+ val=new Value(5123456789l);
+ if(val.getType()!=Value.LONG){
+ err("Numerical type incorrect");
+ }else{
+ if(!val.getTypeName().equals("long")){
+ err("Type name incorrect");
+ }else{
+ if(val.getLong()!=5123456789l){
+ err("Returned value incorrect");
+ }else ok();
+ }
+ }
+
+ out(2,"Float");
+ val=new Value(3.141592f);
+ if(val.getType()!=Value.FLOAT){
+ err("Numerical type incorrect");
+ }else{
+ if(!val.getTypeName().equals("float")){
+ err("Type name incorrect");
+ }else{
+ if(val.getFloat()!=3.141592f){
+ err("Returned value incorrect");
+ }else ok();
+ }
+ }
+
+ out(2,"Double");
+ val=new Value(3.141592653689793284626433d);
+ if(val.getType()!=Value.DOUBLE){
+ err("Numerical type incorrect");
+ }else{
+ if(!val.getTypeName().equals("double")){
+ err("Type name incorrect");
+ }else{
+ if(val.getDouble()!=3.141592653689793284626433d){
+ err("Returned value incorrect");
+ }else ok();
+ }
+ }
+
+ out(2,"Boolean");
+ val=new Value(true);
+ if(val.getType()!=Value.BOOLEAN){
+ err("Numerical type incorrect");
+ }else{
+ if(!val.getTypeName().equals("boolean")){
+ err("Type name incorrect");
+ }else{
+ if(val.getBoolean()!=true){
+ err("Returned value incorrect");
+ }else ok();
+ }
+ }
+
+ out(2,"Binary");
+ byte[] abuf=new byte[10];
+ abuf[0]=0;
+ abuf[1]=1;
+ abuf[2]=2;
+ abuf[3]=3;
+ abuf[4]=4;
+ abuf[5]=5;
+ abuf[6]=6;
+ abuf[7]=7;
+ abuf[8]=8;
+ abuf[9]=9;
+ val=new Value(abuf);
+ if(val.getType()!=Value.BINARY){
+ err("Numerical type incorrect");
+ }else{
+ if(!val.getTypeName().equals("binary")){
+ err("Type name incorrect");
+ }else{
+ if(val.getBinary()[9]!=9){
+ err("Returned value incorrect");
+ }else ok();
+ }
+ }
+
+ outbr(1,"Stream reading and writing");
+ try{
+ out(2,"Writing to stream");
+ ByteArrayOutputStream bout=new ByteArrayOutputStream();
+ DataOutputStream dout=new DataOutputStream(bout);
+
+ Value val1=new Value();
+ Value val2=new Value("foo");
+ Value val3=new Value(1234);
+ Value val4=new Value(5123456789l);
+ Value val5=new Value(3.1415f);
+ Value val6=new Value(3.141592653689793284626433d);
+ Value val7=new Value(true);
+ Value val8=new Value(abuf);
+
+ val1.writeToStream(dout);
+ val2.writeToStream(dout);
+ val3.writeToStream(dout);
+ val4.writeToStream(dout);
+ val5.writeToStream(dout);
+ val6.writeToStream(dout);
+ val7.writeToStream(dout);
+ val8.writeToStream(dout);
+ dout.flush();
+
+ ok();
+
+ out(2,"Reading from stream");
+ byte[] buf=bout.toByteArray();
+ DataInputStream din=new DataInputStream(new ByteArrayInputStream(buf));
+ val1=Value.readFromStream(din);
+ val2=Value.readFromStream(din);
+ val3=Value.readFromStream(din);
+ val4=Value.readFromStream(din);
+ val5=Value.readFromStream(din);
+ val6=Value.readFromStream(din);
+ val7=Value.readFromStream(din);
+ val8=Value.readFromStream(din);
+ ok();
+
+ out(2,"Verifying values");
+ if(val1.getType()!=Value.NULL){
+ err("Wrong value returned for null");
+ }else{
+ if(!val2.getString().equals("foo")){
+ err("Wrong value returned for string");
+ }else{
+ if(val3.getInt()!=1234){
+ err("Wrong value returned for int");
+ }else{
+ if(val4.getLong()!=5123456789l){
+ err("Wrong value returned for long");
+ }else{
+ if(val5.getFloat()!=3.1415f){
+ err("Wrong value returned for float");
+ }else{
+ if(val6.getDouble()!=3.141592653689793284626433d){
+ err("Wrong value returned for double");
+ }else{
+ if(val7.getBoolean()!=true){
+ err("Wrong value returned for boolean");
+ }else{
+ if(val8.getBinary()[9]!=9){
+ err("Wrong value returned for binary");
+ }else ok();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }catch(Exception e){
+ err("Failed with exception "+e);
+ }
+
+ outbr(1,"Value comparisons");
+ out(2,"Equals");
+ Value val1a=new Value();
+ Value val2a=new Value("foo");
+ Value val3a=new Value(1234);
+ Value val4a=new Value(5123456789l);
+ Value val5a=new Value(3.1415f);
+ Value val6a=new Value(3.141592653689793284626433d);
+ Value val7a=new Value(true);
+
+ Value val1b=new Value();
+ Value val2b=new Value("foo");
+ Value val3b=new Value(1234);
+ Value val4b=new Value(5123456789l);
+ Value val5b=new Value(3.1415f);
+ Value val6b=new Value(3.141592653689793284626433d);
+ Value val7b=new Value(true);
+
+ if(!val1a.equals(val1b)){
+ err("Null values not compared correctly");
+ }else if(!val2a.equals(val2b)){
+ err("String values not compared correctly");
+ }else if(!val3a.equals(val3b)){
+ err("Int values not compared correctly");
+ }else if(!val4a.equals(val4b)){
+ err("Long values not compared correctly");
+ }else if(!val5a.equals(val5b)){
+ err("Float values not compared correctly");
+ }else if(!val6a.equals(val6b)){
+ err("Double values not compared correctly");
+ }else if(!val7a.equals(val7b)){
+ err("Boolean values not compared correctly");
+ }else ok();
+
+ out(2,"Greater than");
+ val3b=new Value(2234);
+ val4b=new Value(6123456789l);
+ val5b=new Value(4.1415f);
+ val6b=new Value(4.141592653689793284626433d);
+ if(val3a.greaterThan(val3b)){
+ err("Int values not compared correctly");
+ }else if(val4a.greaterThan(val4b)){
+ err("Long values not compared correctly");
+ }else if(val5a.greaterThan(val5b)){
+ err("Float values not compared correctly");
+ }else if(val6a.greaterThan(val6b)){
+ err("Double values not compared correctly");
+ }else ok();
+
+ out(2,"Less than");
+ val3b=new Value(2234);
+ val4b=new Value(6123456789l);
+ val5b=new Value(4.1415f);
+ val6b=new Value(4.141592653689793284626433d);
+ if(!val3a.lessThan(val3b)){
+ err("Int values not compared correctly");
+ }else if(!val4a.lessThan(val4b)){
+ err("Long values not compared correctly");
+ }else if(!val5a.lessThan(val5b)){
+ err("Float values not compared correctly");
+ }else if(!val6a.lessThan(val6b)){
+ err("Double values not compared correctly");
+ }else ok();
+
+ out(2,"Contains");
+ val1a=new Value("FooBarBaz");
+ val2a=new Value("Bar");
+ if(!val1a.contains(val2a)){
+ err("String values not compared correctly");
+ }else ok();
+
+ out(2,"Starts with");
+ val1a=new Value("FooBarBaz");
+ val2a=new Value("Foo");
+ if(!val1a.startsWith(val2a)){
+ err("String values not compared correctly");
+ }else ok();
+
+ out(2,"Ends with");
+ val1a=new Value("FooBarBaz");
+ val2a=new Value("Baz");
+ if(!val1a.endsWith(val2a)){
+ err("String values not compared correctly");
+ }else ok();
+
+ out(2,"CompareTo");
+ val1a=new Value(1);
+ val2a=new Value(2);
+ if(val1a.compareTo(val2a)!=-1){
+ err("CompareTo did not return -1");
+ }else if(val2a.compareTo(val1a)!=1){
+ err("CompareTo did not return 1");
+ }else{
+ val2a=new Value(1);
+ if(val1a.compareTo(val2a)!=0){
+ err("CompareTo did not return 0");
+ }else ok();
+ }
+
+
+ printErrorSummary();
+ }
+
+ public static void main(String args[]){
+ ValueTest valuet=new ValueTest();
+ valuet.runTest();
+ }
+}
\ No newline at end of file