--- /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
+ */
+
+
+ /**
+ * 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;
+
+ }
+ 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){
+ System.out.println("file a " + getFileName(FILEA));
+ 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){
+ System.out.println("file b " + getFileName(FILEB));
+ 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){
+ // System.out.println("in h");
+ synchronized(indexcache){
+ entry=getCacheEntry(id);
+ // System.out.println(entry);
+ 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;
+ // System.out.println(entry);
+ 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.io.*;
+import java.util.*;
+import java.nio.channels.*;
+import com.solidosystems.tuplesoup.filter.*;
+import dstm2.atomic;
+import dstm2.Thread;
+import dstm2.factory.Factory;
+import dstm2.util.StringKeyHashMap;
+import java.util.concurrent.Callable;
+
+/**
+ * The table stores a group of rows.
+ * Every row must have a unique id within a table.
+ */
+public class DualFileTableTransactional implements TableTransactional{
+
+
+ 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 TableIndexTransactional index=null;
+
+// private long fileaposition=0;
+ // private long filebposition=0;
+
+ private boolean rowswitch=true;
+
+ private String title;
+ private String location;
+
+ private TableIndexNodeTransactional indexcachefirst;
+ private TableIndexNodeTransactional indexcachelast;
+ //private int indexcacheusage;
+
+ private StringKeyHashMap<TableIndexNodeTransactional> indexcache;
+ //private Hashtable<String,TableIndexNode> indexcache;
+
+ static Factory<DualFileTableTSInf> factory = Thread.makeFactory(DualFileTableTSInf.class);
+ // static Factory<FinancialTransactionDS> factory = Thread.makeFactory(FinancialTransactionDS.class);
+ DualFileTableTSInf atomicfields;
+ // Statistic counters
+
+ public @atomic interface DualFileTableTSInf{
+ Long getstat_add();
+ Long getstat_update();
+ Long getstat_delete();
+ Long getstat_add_size();
+ Long getstat_update_size();
+ Long getstat_read_size();
+ Long getstat_read();
+ Long getstat_cache_hit();
+ Long getstat_cache_miss();
+ Long getstat_cache_drop();
+ Long getFileaposition();
+ Long getFilebposition();
+ Integer getIndexcacheusage();
+
+ void setstat_add(Long val);
+ void setstat_update(Long val);
+ void setstat_delete(Long val);
+ void setstat_add_size(Long val);
+ void setstat_update_size(Long val);
+ void setstat_read_size(Long val);
+ void setstat_read(Long val);
+ void setstat_cache_hit(Long val);
+ void setstat_cache_miss(Long val);
+ void setstat_cache_drop(Long val);
+ void setIndexcacheusage(Integer val);
+ void setFileaposition(Long val);
+ void setFilebposition(Long val);
+ }
+
+ /*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(){
+
+ // synchronized(statlock){
+ return Thread.doIt(new Callable<Hashtable<String,Long>>() {
+ public Hashtable<String,Long> call() throws Exception{
+ Hashtable<String,Long> hash=new Hashtable<String,Long>();
+ hash.put("stat_table_add",atomicfields.getstat_add());
+ hash.put("stat_table_update",atomicfields.getstat_update());
+ hash.put("stat_table_delete",atomicfields.getstat_delete());
+ hash.put("stat_table_add_size",atomicfields.getstat_add_size());
+ hash.put("stat_table_update_size",atomicfields.getstat_update_size());
+ hash.put("stat_table_read_size",atomicfields.getstat_read_size());
+ hash.put("stat_table_read",atomicfields.getstat_read());
+ hash.put("stat_table_cache_hit",atomicfields.getstat_cache_hit());
+ hash.put("stat_table_cache_miss",atomicfields.getstat_cache_miss());
+ hash.put("stat_table_cache_drop",atomicfields.getstat_cache_drop());
+ atomicfields.setstat_add(Long.valueOf(0));
+ atomicfields.setstat_update(Long.valueOf(0));
+ atomicfields.setstat_delete(Long.valueOf(0));
+ atomicfields.setstat_add_size(Long.valueOf(0));
+ atomicfields.setstat_update_size(Long.valueOf(0));
+ atomicfields.setstat_read_size(Long.valueOf(0));
+ atomicfields.getstat_read_size();
+ atomicfields.setstat_read(Long.valueOf(0));
+ atomicfields.setstat_cache_hit(Long.valueOf(0));
+ atomicfields.setstat_cache_miss(Long.valueOf(0));
+ atomicfields.setstat_cache_drop(Long.valueOf(0));
+ Hashtable<String,Long> ihash=index.readStatistics();
+ hash.putAll(ihash);
+ return hash;
+ }
+ });
+
+ }
+
+ /**
+ * Create a new table object with the default flat index model
+ */
+
+
+ /**
+ * Create a new table object with a specific index model
+ */
+ public DualFileTableTransactional(String title,String location, int indextype) throws IOException{
+ atomicfields = factory.create();
+
+ this.title=title;
+ this.location=location;
+ if(!this.location.endsWith(File.separator))this.location+=File.separator;
+ switch(indextype){
+ case PAGED : index=new PagedIndexTransactional(getFileName(INDEX));
+ break;
+
+ }
+ indexcachefirst=null;
+ indexcachelast=null;
+ atomicfields.setFileaposition(Long.valueOf(0));
+ atomicfields.setFilebposition(Long.valueOf(0));
+ atomicfields.setstat_update_size(Long.valueOf(0));
+ atomicfields.setstat_update(Long.valueOf(0));
+ atomicfields.setstat_read_size(Long.valueOf(0));
+ atomicfields.setstat_read(Long.valueOf(0));
+ atomicfields.setstat_delete(Long.valueOf(0));
+ atomicfields.setstat_cache_miss(Long.valueOf(0));
+ atomicfields.setstat_cache_hit(Long.valueOf(0));
+ atomicfields.setstat_cache_drop(Long.valueOf(0));
+ atomicfields.setstat_add_size(Long.valueOf(0));
+ atomicfields.setstat_add(Long.valueOf(0));
+ atomicfields.setIndexcacheusage(Integer.valueOf(0));
+ indexcache=new StringKeyHashMap<TableIndexNodeTransactional>();
+ }
+
+ /**
+ * 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){
+ System.out.println("file a " + getFileName(FILEA));
+ fileastream=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(getFileName(FILEA),true)));
+ File ftest=new File(getFileName(FILEA));
+ atomicfields.setFileaposition(ftest.length());
+ }
+ break;
+ case FILEB : if(filebstream==null){
+ System.out.println("file b " + getFileName(FILEB));
+ filebstream=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(getFileName(FILEB),true)));
+ File ftest=new File(getFileName(FILEB));
+ atomicfields.setFilebposition(ftest.length());
+ }
+ break;
+ }
+
+ }
+
+ /**
+ * Adds a row of data to this table.
+ */
+ public void addRow(RowTransactional 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(TableIndexEntryTransactional entry){
+ // synchronized(indexcache){
+ if(atomicfields.getIndexcacheusage()>INDEXCACHESIZE){
+ // remove first entry
+ TableIndexNodeTransactional node=indexcachefirst;
+ indexcache.remove(node.getData().getId());
+ atomicfields.setIndexcacheusage(atomicfields.getIndexcacheusage()-1);
+ // synchronized(statlock){
+ atomicfields.setstat_cache_drop(atomicfields.getstat_cache_drop()+1);
+ // }
+ indexcachefirst=node.getNext();
+ if(indexcachefirst==null){
+ indexcachelast=null;
+ }else{
+ indexcachefirst.setPrevious(null);
+ }
+ }
+ TableIndexNodeTransactional node=new TableIndexNodeTransactional(indexcachelast,entry);
+ if(indexcachelast!=null){
+ indexcachelast.setNext(node);
+ }
+ if(indexcachefirst==null){
+ indexcachefirst=node;
+ }
+ indexcachelast=node;
+ indexcache.put(entry.getId(),node);
+ atomicfields.setIndexcacheusage(atomicfields.getIndexcacheusage()+1);
+ // }
+ }
+
+ private synchronized void addRowA(RowTransactional row) throws IOException{
+ synchronized(filealock){
+ synchronized(index){
+ final Vector args = new Vector();
+ args.add(row);
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+ openFile(FILEA);
+ int pre=fileastream.size();
+ ((RowTransactional)args.get(0)).writeToStream(fileastream);
+ int post=fileastream.size();
+ fileastream.flush();
+
+ //synchronized(statlock){
+ atomicfields.setstat_add(atomicfields.getstat_add()+1);
+ atomicfields.setstat_add_size(atomicfields.getstat_add_size()+((RowTransactional)args.get(0)).getSize());
+ //}
+
+ index.addEntry(((RowTransactional)args.get(0)).getId(),((RowTransactional)args.get(0)).getSize(),FILEA,atomicfields.getFilebposition());
+ if(INDEXCACHESIZE>0){
+ TableIndexEntryTransactional entry=new TableIndexEntryTransactional(((RowTransactional)args.get(0)).getId(),((RowTransactional)args.get(0)).getSize(),FILEA,atomicfields.getFileaposition());
+ addCacheEntry(entry);
+ }
+ atomicfields.setFileaposition(atomicfields.getFileaposition()+RowTransactional.calcSize(pre,post));
+ return true;
+ }
+ });
+ }
+ }
+ }
+ private synchronized void addRowB(RowTransactional row) throws IOException{
+ synchronized(fileblock){
+ synchronized(index){
+
+ final Vector args = new Vector();
+ args.add(row);
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+ openFile(FILEB);
+ int pre=filebstream.size();
+ ((RowTransactional)args.get(0)).writeToStream(filebstream);
+ int post=filebstream.size();
+ filebstream.flush();
+ //int post=filebstream.size();
+ //filebstream.flush();
+ //synchronized(statlock){
+ atomicfields.setstat_add(atomicfields.getstat_add()+1);
+ atomicfields.setstat_add_size(atomicfields.getstat_add_size()+((RowTransactional)args.get(0)).getSize());
+ // }
+ index.addEntry(((RowTransactional)args.get(0)).getId(),((RowTransactional)args.get(0)).getSize(),FILEB,atomicfields.getFilebposition());
+ if(INDEXCACHESIZE>0){
+ TableIndexEntryTransactional entry=new TableIndexEntryTransactional(((RowTransactional)args.get(0)).getId(),((RowTransactional)args.get(0)).getSize(),FILEB,atomicfields.getFilebposition());
+ addCacheEntry(entry);
+ }
+ atomicfields.setFilebposition(atomicfields.getFilebposition()+RowTransactional.calcSize(pre,post));
+ return true;
+ }
+ });
+ }
+ }
+ }
+
+
+ private void updateCacheEntry(TableIndexEntryTransactional entry){
+
+ //synchronized(indexcache){
+ if(indexcache.containsKey(entry.getId())){
+ TableIndexNodeTransactional 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);
+ }
+ // return true;
+ // }
+ // });
+ }
+
+ private void removeCacheEntry(String id){
+ //synchronized(indexcache){
+ final Vector args = new Vector();
+ args.add(id);
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+
+ if(indexcache.containsKey((String)(args.get(0)))){
+ TableIndexNodeTransactional node=indexcache.get((String)(args.get(0)));
+ indexcache.remove((String)(args.get(0)));
+ if(atomicfields.getIndexcacheusage()==1){
+ indexcachefirst=null;
+ indexcachelast=null;
+ atomicfields.setIndexcacheusage(0);
+ return true;
+ }
+ if(node==indexcachefirst){
+ indexcachefirst=node.getNext();
+ indexcachefirst.setPrevious(null);
+ }else if(node==indexcachelast){
+ indexcachelast=node.getPrevious();
+ indexcachelast.setNext(null);
+ }else{
+ node.remove();
+ }
+ atomicfields.setIndexcacheusage(atomicfields.getIndexcacheusage()-1);
+ // synchronized(statlock){
+ atomicfields.setstat_cache_drop(atomicfields.getstat_cache_drop()+1);
+
+ // }
+ }
+ return true;
+ }
+ });
+ }
+
+ private TableIndexEntryTransactional getCacheEntry(String id){
+
+ //synchronized(indexcache){
+ if(indexcache.containsKey(id)){
+ TableIndexNodeTransactional 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){
+ atomicfields.setstat_cache_hit(atomicfields.getstat_cache_hit()+1);
+ // }
+ return node.getData();
+ }
+
+ //synchronized(statlock){
+ atomicfields.setstat_cache_miss(atomicfields.getstat_cache_miss()+1);
+
+ //}
+ 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(RowTransactional row) throws IOException{
+ RowTransactional tmprow=getRow(row.getId());
+ if(tmprow==null){
+ addRow(row);
+ }else{
+ updateRow(row);
+ }
+ }
+
+ /**
+ * Updates a row stored in this table.
+ */
+ public void updateRow(RowTransactional row) throws IOException{
+ TableIndexEntryTransactional entry=null;
+ final Vector args = new Vector();
+ args.add(row);
+
+ // Handle index entry caching
+ if(INDEXCACHESIZE>0){
+ synchronized (index){
+ entry = Thread.doIt(new Callable<TableIndexEntryTransactional>() {
+ public TableIndexEntryTransactional call() throws Exception {
+ TableIndexEntryTransactional entry;// = (TableIndexEntryTransactional) (args.get(1));
+ RowTransactional row = (RowTransactional) (args.get(0));
+ entry = getCacheEntry(row.getId());
+ if(entry==null){
+ entry=index.scanIndex(row.getId());
+ addCacheEntry(entry);
+ }
+ return entry;
+ }
+ });
+ }
+ /* synchronized(indexcache){
+ entry=getCacheEntry(row.getId());
+ if(entry==null){
+ entry=index.scanIndex(row.getId());
+ addCacheEntry(entry);
+ }
+ }*/
+ }else{
+ entry=index.scanIndexTransactional(row.getId());
+ }
+ args.add(entry);
+ if(entry.getRowSize()>=row.getSize()){
+ // Add to the existing location
+ switch(entry.getLocation()){
+ case FILEA :
+ synchronized(filealock){
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ if(filearandom==null){
+ filearandom=new RandomAccessFile(getFileName(FILEA),"rw");
+ // fca=filearandom.getChannel();
+ }
+ filearandom.seek(((TableIndexEntryTransactional) (args.get(1))).getPosition());
+ ((RowTransactional) (args.get(0))).writeToFile(filearandom);
+ fca.force(false);
+ return true;
+
+ }
+ });
+ }
+ break;
+ case FILEB :
+ synchronized(fileblock){
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ if(filebrandom==null){
+ filebrandom=new RandomAccessFile(getFileName(FILEB),"rw");
+ fcb=filebrandom.getChannel();
+ }
+ filebrandom.seek(((TableIndexEntryTransactional) (args.get(1))).getPosition());
+ ((RowTransactional) (args.get(0))).writeToFile(filebrandom);
+ fcb.force(false);
+ return true;
+ }
+ });
+ }
+ break;
+ }
+ }else{
+ if(rowswitch){
+ updateRowA(row);
+ }else{
+ updateRowB(row);
+ }
+ rowswitch=!rowswitch;
+ }
+ //synchronized(statlock){
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+ atomicfields.setstat_update(atomicfields.getstat_update()+1);
+ atomicfields.setstat_update_size(atomicfields.getstat_update_size()+((RowTransactional) (args.get(0))).getSize());
+ return true;
+ }
+ });
+ }
+
+ private synchronized void updateRowA(RowTransactional row) throws IOException{
+ final Vector args = new Vector();
+ args.add(row);
+ System.out.println("b");
+ synchronized(filealock){
+ synchronized (index){
+ // synchronized (index){
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+
+ System.out.println("add a");
+ openFile(FILEA);
+ int pre=filebstream.size();
+ ((RowTransactional)(args.get(0))).writeToStream(fileastream);
+ int post=filebstream.size();
+ fileastream.flush();
+ index.updateEntry(((RowTransactional)(args.get(0))).getId(),((RowTransactional)(args.get(0))).getSize(),FILEA,atomicfields.getFileaposition());
+
+ // Handle index entry caching
+ if(INDEXCACHESIZE>0){
+ updateCacheEntry(new TableIndexEntryTransactional(((RowTransactional)(args.get(0))).getId(),((RowTransactional)(args.get(0))).getSize(),FILEA,atomicfields.getFileaposition()));
+ }
+ atomicfields.setFileaposition(atomicfields.getFilebposition()+RowTransactional.calcSize(pre,post));
+ return true;
+ }
+ });
+ // }
+ }
+ }
+ }
+
+ private synchronized void updateRowB(RowTransactional row) throws IOException{
+ final Vector args = new Vector();
+ System.out.println("b");
+ args.add(row);
+ synchronized(fileblock){
+ synchronized (index){
+ //synchronized (index){
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+ System.out.println("add b");
+
+ openFile(FILEB);
+ int pre=filebstream.size();
+ ((RowTransactional)(args.get(0))).writeToStream(filebstream);
+ int post=filebstream.size();
+ filebstream.flush();
+ index.updateEntry(((RowTransactional)(args.get(0))).getId(),((RowTransactional)(args.get(0))).getSize(),FILEB,atomicfields.getFilebposition());
+ // Handle index entry caching
+ // Handle index entry caching
+ if(INDEXCACHESIZE>0){
+ updateCacheEntry(new TableIndexEntryTransactional(((RowTransactional)(args.get(0))).getId(),((RowTransactional)(args.get(0))).getSize(),FILEB,atomicfields.getFilebposition()));
+ }
+ atomicfields.setFilebposition(atomicfields.getFilebposition()+RowTransactional.calcSize(pre,post));
+ return true;
+ }
+ });
+ // }
+ }
+ }
+ }
+
+ /**
+ * Marks a row as deleted in the index.
+ * Be aware that the space consumed by the row is not actually reclaimed.
+ */
+ public void deleteRow(RowTransactional row) throws IOException{
+ // Handle index entry caching
+ if(INDEXCACHESIZE>0){
+ removeCacheEntry(row.getId());
+ }
+ index.updateEntryTransactional(row.getId(),row.getSize(),DELETE,0);
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+ //synchronized(statlock){
+ atomicfields.setstat_delete(atomicfields.getstat_delete()+1);
+ return true;
+ }
+ });
+ // }
+ }
+
+ /**
+ * Returns a tuplestream containing the given list of rows
+ */
+ public TupleStreamTransactional getRows(List<String> rows) throws IOException{
+ return new IndexedTableReaderTransactional(this,index.scanIndex(rows));
+ }
+
+ /**
+ * Returns a tuplestream containing the rows matching the given rowmatcher
+ */
+ public TupleStreamTransactional getRows(RowMatcherTransactional matcher) throws IOException{
+ return new IndexedTableReaderTransactional(this,index.scanIndex(),matcher);
+ }
+
+ /**
+ * Returns a tuplestream containing those rows in the given list that matches the given RowMatcher
+ */
+ public TupleStreamTransactional getRows(List<String> rows,RowMatcherTransactional matcher) throws IOException{
+ return new IndexedTableReaderTransactional(this,index.scanIndex(rows),matcher);
+ }
+
+ /**
+ * Returns a tuplestream of all rows in this table.
+ */
+ public TupleStreamTransactional getRows() throws IOException{
+ // return new TableReader(this);
+ return new IndexedTableReaderTransactional(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 RowTransactional getRow(String id) throws IOException{
+ TableIndexEntryTransactional entry=null;
+ final Vector args = new Vector();
+ args.add(id);
+ // args.add(entry);
+ // Handle index entry caching
+ if(INDEXCACHESIZE>0){
+
+ //synchronized(indexcache){
+ synchronized (index){
+ entry = Thread.doIt(new Callable<TableIndexEntryTransactional>() {
+ public TableIndexEntryTransactional call() throws Exception{
+ TableIndexEntryTransactional entry;// = (TableIndexEntryTransactional) (args.get(1));
+ String id = (String) (args.get(0));
+ entry=getCacheEntry(id);
+ // System.out.println("presalam " + (TableIndexEntryTransactional) (args.get(1)));
+ if(entry==null){
+ entry=index.scanIndex(id);
+ if(entry!=null){
+ addCacheEntry(entry);
+ }
+ }
+ return entry;
+ }
+ });
+ }
+
+ }else{
+ entry=index.scanIndexTransactional(id);
+ }
+// entry = (TableIndexEntryTransactional) (args.get(1));
+ // args.clear();
+
+ if(entry!=null){
+ long dataoffset=0;
+ DataInputStream data=null;
+
+ if(entry.getLocation()==TableTransactional.FILEA){
+ data=new DataInputStream(new BufferedInputStream(new FileInputStream(getFileName(TableTransactional.FILEA))));
+ }else if(entry.getLocation()==TableTransactional.FILEB){
+ data=new DataInputStream(new BufferedInputStream(new FileInputStream(getFileName(TableTransactional.FILEB))));
+ }
+ if(data!=null){
+ while(dataoffset!=entry.getPosition()){
+ dataoffset+=data.skipBytes((int)(entry.getPosition()-dataoffset));
+ }
+ RowTransactional row=RowTransactional.readFromStream(data);
+ data.close();
+ final Vector args2 = new Vector();
+ args2.add(row);
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+ //synchronized(statlock){
+ atomicfields.setstat_read(atomicfields.getstat_read()+1);
+ atomicfields.setstat_read_size(atomicfields.getstat_read_size()+((RowTransactional)args2.get(0)).getSize());
+ return true;
+ }
+ });
+ 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.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=5;
+ private List<Table> tableset;
+ private String title;
+ private String 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 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 HashedTableTransactional implements TableTransactional{
+ private int TABLESETSIZE=5;
+ private List<TableTransactional> tableset;
+ private String title;
+ private String location;
+
+
+
+ /**
+ * Create a new table object with a specific index model
+ */
+ public HashedTableTransactional(String title,String location, int indextype) throws IOException{
+ this.title=title;
+ this.location=location;
+ tableset=new ArrayList<TableTransactional>();
+ for(int i=0;i<TABLESETSIZE;i++){
+ tableset.add(new DualFileTableTransactional(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 TableTransactional 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 RowTransactional getRow(String id) throws IOException{
+ TableTransactional tbl=getTableForId(id);
+ return tbl.getRow(id);
+ }
+
+ /**
+ * Returns a tuplestream of all rows in this table.
+ */
+ public TupleStreamTransactional getRows() throws IOException{
+ TupleStreamMergerTransactional merge=new TupleStreamMergerTransactional();
+ 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 TupleStreamTransactional 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);
+ }
+ TupleStreamMergerTransactional merge=new TupleStreamMergerTransactional();
+ 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 TupleStreamTransactional getRows(RowMatcherTransactional matcher) throws IOException{
+ TupleStreamMergerTransactional merge=new TupleStreamMergerTransactional();
+ 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 TupleStreamTransactional getRows(List<String> rows,RowMatcherTransactional 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);
+ }
+ TupleStreamMergerTransactional merge=new TupleStreamMergerTransactional();
+ 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(RowTransactional row) throws IOException{
+ getTableForId(row.getId()).deleteRow(row);
+ }
+
+ /**
+ * Adds a row of data to this table.
+ */
+ public void addRow(RowTransactional 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(RowTransactional row) throws IOException{
+ getTableForId(row.getId()).addOrUpdateRow(row);
+ }
+
+ /**
+ * Updates a row stored in this table.
+ */
+ public void updateRow(RowTransactional 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 com.solidosystems.tuplesoup.filter.*;
+ import java.io.*;
+ import java.util.*;
+ import java.util.concurrent.Callable;
+ import dstm2.Thread;
+
+
+public class IndexedTableReaderTransactional extends TupleStreamTransactional{
+
+
+
+
+ private DataInputStream fileastream=null;
+ private DataInputStream filebstream=null;
+ private long fileaposition=0;
+ private long filebposition=0;
+
+ private List<TableIndexEntryTransactional>fileaentries;
+ private List<TableIndexEntryTransactional>filebentries;
+
+ private List<TableIndexEntryTransactional>entries;
+
+ private Hashtable<String,RowTransactional>fileabuffer;
+ private Hashtable<String,RowTransactional>filebbuffer;
+
+ private List<String>rows;
+ private int rowpointer;
+ private RowTransactional next=null;
+
+ private DualFileTableTransactional table;
+
+ private RowMatcherTransactional matcher=null;
+
+ public IndexedTableReaderTransactional(DualFileTableTransactional table,List<TableIndexEntryTransactional>entries) throws IOException{
+ this.table=table;
+ this.rows=rows;
+ rowpointer=0;
+
+ this.entries=entries;
+ fileaentries=new ArrayList<TableIndexEntryTransactional>();
+ filebentries=new ArrayList<TableIndexEntryTransactional>();
+
+ Iterator<TableIndexEntryTransactional> it=entries.iterator();
+ while(it.hasNext()){
+ TableIndexEntryTransactional entry=it.next();
+ // TODO: we really shouldn't get nulls here
+ if(entry!=null){
+ if(entry.getLocation()==TableTransactional.FILEA){
+ fileaentries.add(entry);
+ }else if(entry.getLocation()==TableTransactional.FILEB){
+ filebentries.add(entry);
+ }
+ }
+ }
+
+ Collections.sort(fileaentries);
+ Collections.sort(filebentries);
+
+ fileabuffer=new Hashtable<String,RowTransactional>();
+ filebbuffer=new Hashtable<String,RowTransactional>();
+
+ readNext();
+ }
+
+
+ public IndexedTableReaderTransactional(DualFileTableTransactional table,List<TableIndexEntryTransactional>entries,RowMatcherTransactional matcher) throws IOException{
+ this.table=table;
+ this.rows=rows;
+ rowpointer=0;
+ this.matcher=matcher;
+
+ this.entries=entries;
+ fileaentries=new ArrayList<TableIndexEntryTransactional>();
+ filebentries=new ArrayList<TableIndexEntryTransactional>();
+
+ Iterator<TableIndexEntryTransactional> it=entries.iterator();
+ while(it.hasNext()){
+ TableIndexEntryTransactional entry=it.next();
+ // TODO: we really shouldn't get nulls here
+ if(entry!=null){
+ if(entry.getLocation()==TableTransactional.FILEA){
+ fileaentries.add(entry);
+ }else if(entry.getLocation()==TableTransactional.FILEB){
+ filebentries.add(entry);
+ }
+ }
+ }
+
+ Collections.sort(fileaentries);
+ Collections.sort(filebentries);
+
+ fileabuffer=new Hashtable<String,RowTransactional>();
+ filebbuffer=new Hashtable<String,RowTransactional>();
+
+ readNext();
+ }
+
+ private void readNextFromFileA(TableIndexEntryTransactional entry) throws IOException{
+ if(fileabuffer.containsKey(entry.getId())){
+ next=fileabuffer.remove(entry.getId());
+ return;
+ }
+ while(true){
+ if(fileaentries.size()>0){
+ TableIndexEntryTransactional nextfilea=fileaentries.remove(0);
+ if(fileastream==null){
+ // fileastream=new TransactionalFile(table.getFileName(TableTransactional.FILEA), "rw");
+ fileastream=new DataInputStream(new BufferedInputStream(new FileInputStream(table.getFileName(TableTransactional.FILEA))));
+ fileaposition=0;
+ }
+ if(fileaposition>nextfilea.getPosition()){
+ // We have already read this entry... skip it
+ // readNextFromFileA(entry);
+ // return;
+ }else{
+ while(fileaposition!=nextfilea.getPosition()){
+ fileaposition+=fileastream.skipBytes((int)(nextfilea.getPosition()-fileaposition));
+ }
+
+ RowTransactional row=RowTransactional.readFromStream(fileastream);
+ final Vector args = new Vector();
+ args.add(row);
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+ //synchronized(table.statlock){
+ table.atomicfields.setstat_read_size(table.atomicfields.getstat_read_size()+((RowTransactional)(args.get(0))).getSize());
+ table.atomicfields.setstat_read(table.atomicfields.getstat_read()+1);
+ return true;
+ }
+ //}
+ });
+
+ fileaposition+=row.getSize();
+ if(row.getId().equals(entry.getId())){
+ next=row;
+ return;
+ }else{
+ fileabuffer.put(row.getId(),row);
+ // readNextFromFileA(entry);
+ }
+ }
+ }else{
+ next=null;
+ return;
+ }
+ }
+ }
+
+ private void readNextFromFileB(TableIndexEntryTransactional entry) throws IOException{
+ if(filebbuffer.containsKey(entry.getId())){
+ next=filebbuffer.remove(entry.getId());
+ return;
+ }
+ while(true){
+ if(filebentries.size()>0){
+ TableIndexEntryTransactional nextfileb=filebentries.remove(0);
+ if(filebstream==null){
+ filebstream=new DataInputStream(new BufferedInputStream(new FileInputStream(table.getFileName(TableTransactional.FILEB))));
+ filebposition=0;
+ }
+ if(filebposition>nextfileb.getPosition()){
+ // We have already read this entry... skip it
+ // readNextFromFileB(entry);
+ // return;
+ }else{
+ while(filebposition!=nextfileb.getPosition()){
+ filebposition+=filebstream.skipBytes((int)(nextfileb.getPosition()-filebposition));
+ }
+ RowTransactional row=RowTransactional.readFromStream(filebstream);
+
+ final Vector args = new Vector();
+ args.add(row);
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+ //synchronized(table.statlock){
+ table.atomicfields.setstat_read_size(table.atomicfields.getstat_read_size()+((RowTransactional)(args.get(0))).getSize());
+ table.atomicfields.setstat_read(table.atomicfields.getstat_read()+1);
+ return true;
+ }
+ });
+
+ filebposition+=row.getSize();
+ if(row.getId().equals(entry.getId())){
+ next=row;
+ return;
+ }else{
+ filebbuffer.put(row.getId(),row);
+ // readNextFromFileB(entry);
+ }
+ }
+ }else{
+ next=null;
+ return;
+ }
+ }
+ }
+
+ private void readNext() throws IOException{
+ if(entries.size()>rowpointer){
+ TableIndexEntryTransactional entry=entries.get(rowpointer++);
+ if(entry!=null){
+ switch(entry.getLocation()){
+ case TableTransactional.FILEA : readNextFromFileA(entry);
+ // return;
+ break;
+ case TableTransactional.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 RowTransactional next(){
+ try{
+ if(next!=null){
+ RowTransactional 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 dstm2.AtomicArray;
+import dstm2.atomic;
+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;
+
+ protected static final int INITIALPAGEHASH=32;
+ protected static final int PAGESIZE=64;
+
+ private RandomAccessFile out=null;
+ private String filename;
+ private TableIndexPage[] root=null;
+ // private TableIndexPageTransactional[] 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];
+ System.out.println(filename);
+ System.out.println(out.length());
+ 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
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+
+import dstm2.AtomicArray;
+import dstm2.atomic;
+import dstm2.Thread;
+import dstm2.factory.Factory;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+import java.util.concurrent.Callable;
+
+/**
+ *
+ * @author navid
+ */
+public class PagedIndexTransactional implements TableIndexTransactional{
+
+ static Factory<PageIndexTSInf> factory = Thread.makeFactory(PageIndexTSInf.class);
+
+ PageIndexTSInf atomicfields;
+
+
+
+ public @atomic interface PageIndexTSInf{
+ String getFilename();
+ Long getStat_read();
+ Long getStat_write();
+ Long getStat_create_page();
+ Long getStat_page_next();
+ Long getStat_page_branch();
+ AtomicArray<TableIndexPageTransactional> getRoots();
+
+ void setFilename(String val);
+ void setRoots(AtomicArray<TableIndexPageTransactional> roots);
+ void setStat_read(Long val);
+ void setStat_write(Long val);
+ void setStat_create_page(Long val);
+ void setStat_page_next(Long val);
+ void setStat_page_branch(Long val);
+ }
+
+
+ private RandomAccessFile out=null;
+
+ //protected static final int INITIALPAGEHASH=1024;
+ //protected static final int PAGESIZE=2048;
+
+ protected static final int INITIALPAGEHASH=32;
+ protected static final int PAGESIZE=64;
+
+ public PagedIndexTransactional(String filename) throws IOException{
+ atomicfields = factory.create();
+
+ atomicfields.setStat_create_page(Long.valueOf(0));
+ atomicfields.setStat_page_branch(Long.valueOf(0));
+ atomicfields.setStat_page_next(Long.valueOf(0));
+ atomicfields.setStat_read(Long.valueOf(0));
+ atomicfields.setStat_write(Long.valueOf(0));
+
+ this.atomicfields.setFilename(filename);
+ File ftest=new File(filename);
+ if(!ftest.exists())ftest.createNewFile();
+ out=new RandomAccessFile(filename,"rw");
+ atomicfields.setRoots(new AtomicArray<TableIndexPageTransactional>(TableIndexPageTransactional.class, INITIALPAGEHASH));
+ // System.out.println(filename);
+ // System.out.println(out.length());
+ if(out.length()>0){
+ for(int i=0;i<INITIALPAGEHASH;i++){
+ atomicfields.getRoots().set(i, new TableIndexPageTransactional(this,out));
+ atomicfields.getRoots().get(i).setFirst();
+ // System.out.println("In loop " + atomicfields.getRoots().get(i).getEndLocation());
+ out.seek(atomicfields.getRoots().get(i).getEndLocation());
+ }
+ }else{
+ for(int i=0;i<INITIALPAGEHASH;i++){
+ atomicfields.getRoots().set(i, TableIndexPageTransactional.createNewPage(this,out,PAGESIZE));
+ // System.out.println("In Othe loop " + atomicfields.getRoots().get(i).getEndLocation());
+ atomicfields.getRoots().get(i).setFirst();
+ }
+ }
+ }
+
+ public Hashtable<String,Long> readStatistics(){
+ Hashtable<String,Long> hash=new Hashtable<String,Long>();
+ hash.put("stat_index_read",atomicfields.getStat_read());
+ hash.put("stat_index_write",atomicfields.getStat_write());
+ hash.put("stat_index_create_page",atomicfields.getStat_create_page());
+ hash.put("stat_index_page_next",atomicfields.getStat_page_next());
+ hash.put("stat_index_page_branch",atomicfields.getStat_page_branch());
+ atomicfields.setStat_read((long)0);
+ atomicfields.setStat_write((long)0);
+ atomicfields.setStat_create_page((long)0);
+ atomicfields.setStat_page_next((long)0);
+ atomicfields.setStat_page_branch((long)0);
+ return hash;
+ }
+
+ private int rootHash(String id){
+ return id.hashCode() & (INITIALPAGEHASH-1);
+ }
+
+ private /*synchronized*/ TableIndexPageTransactional getFirstFreePage(String id) throws IOException{
+ return atomicfields.getRoots().get(rootHash(id)).getFirstFreePage(id, id.hashCode());
+ }
+
+ private /*synchronized*/ long getOffset(String id) throws IOException{
+ if(atomicfields.getRoots()==null)return -1;
+ return atomicfields.getRoots().get(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);
+ TableIndexEntryTransactional entry=new TableIndexEntryTransactional(id,rowsize,location,position);
+ entry.updateData(out);
+ atomicfields.setStat_write(atomicfields.getStat_write()+1);
+ }
+
+ public synchronized void updateEntryTransactional(String id,int rowsize,int location,long position) throws IOException{
+ final String id2 = id;
+ final int rowsize2 = rowsize;
+ final int location2 = location;
+ final long position2 = position;
+
+ Thread.doIt(new Callable<Boolean>() {
+ public Boolean call() throws Exception{
+ long offset=getOffset(id2);
+ out.seek(offset);
+ TableIndexEntryTransactional entry=new TableIndexEntryTransactional(id2,rowsize2,location2,position2);
+ entry.updateData(out);
+ atomicfields.setStat_write(atomicfields.getStat_write()+1);
+ return true;
+ }
+ });
+ }
+
+ public /*synchronized*/ void addEntry(String id,int rowsize,int location,long position) throws IOException{
+ TableIndexPageTransactional page=getFirstFreePage(id);
+ page.addEntry(id,rowsize,location,position);
+ atomicfields.setStat_write(atomicfields.getStat_write()+1);
+ }
+ public /*synchronized*/ TableIndexEntryTransactional scanIndex(String id) throws IOException{
+ if(atomicfields.getRoots()==null)return null;
+ return atomicfields.getRoots().get(rootHash(id)).scanIndex(id,id.hashCode());
+ }
+
+ public synchronized TableIndexEntryTransactional scanIndexTransactional(String id) throws IOException{
+ final String id2 = id;
+ return Thread.doIt(new Callable<TableIndexEntryTransactional>() {
+ public TableIndexEntryTransactional call() throws Exception{
+ if(atomicfields.getRoots()==null)return null;
+ return atomicfields.getRoots().get(rootHash(id2)).scanIndex(id2,id2.hashCode());
+ }
+ });
+ }
+
+ public synchronized List<TableIndexEntryTransactional> scanIndex(List<String> rows) throws IOException{
+ final List<String> rows2 = rows;
+ return Thread.doIt(new Callable<List<TableIndexEntryTransactional>>() {
+ public List<TableIndexEntryTransactional> call() throws Exception{
+ List<TableIndexEntryTransactional> lst=new ArrayList<TableIndexEntryTransactional>();
+ for(int i=0;i<rows2.size();i++){
+ String id=rows2.get(i);
+ TableIndexEntryTransactional entry=scanIndex(id);
+ if(entry!=null){
+ if(entry.getLocation()!=TableTransactional.DELETE)lst.add(entry);
+ }
+ }
+ return lst;
+ }
+ });
+ }
+ public synchronized List<TableIndexEntryTransactional> scanIndex() throws IOException{
+ return Thread.doIt(new Callable<List<TableIndexEntryTransactional>>() {
+ public List<TableIndexEntryTransactional> call() throws Exception{
+ ArrayList<TableIndexEntryTransactional> lst=new ArrayList<TableIndexEntryTransactional>();
+ System.out.println(Thread.currentThread() + " start");
+ for(int i=0;i<INITIALPAGEHASH;i++){
+ atomicfields.getRoots().get(i).addEntriesToList(lst);
+ }
+ System.out.println(Thread.currentThread() +" done");
+ return lst;
+ }
+ });
+ }
+ public void close(){
+ try{
+ if(out!=null){
+ out.close();
+ }
+ }catch(Exception e){}
+ }
+}
--- /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.*;
+
+public class RowMatcherTransactional{
+ 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 ValueTransactional value=null;
+ private int type=-1;
+
+ private RowMatcherTransactional match1=null;
+ private RowMatcherTransactional match2=null;
+
+ public RowMatcherTransactional(String key,int type,ValueTransactional value){
+ this.key=key;
+ this.type=type;
+ this.value=value;
+ }
+
+ public RowMatcherTransactional(String key,int type){
+ this.key=key;
+ this.type=type;
+ }
+
+ public RowMatcherTransactional(RowMatcherTransactional match1,int type,RowMatcherTransactional match2){
+ this.match1=match1;
+ this.type=type;
+ this.match2=match2;
+ }
+
+ public RowMatcherTransactional(int type,RowMatcherTransactional match1){
+ this.match1=match1;
+ this.type=type;
+ }
+
+ /**
+ * This method needs to be seriously optimized... especially the XOR method
+ */
+ public boolean matches(RowTransactional row){
+ if(value!=null){
+ ValueTransactional 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){
+ ValueTransactional 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
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import dstm2.atomic;
+import dstm2.Thread;
+import dstm2.factory.Factory;
+import dstm2.util.StringKeyHashMap;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+/**
+ *
+ * @author navid
+ */
+public class RowTransactional {
+ Factory<RowTSInf> factory = Thread.makeFactory(RowTSInf.class);
+
+ private String id;
+ // private int size;
+ RowTSInf atomicfields;
+ private StringKeyHashMap<ValueTransactional> values;
+
+ public @atomic interface RowTSInf{
+ int getSize();
+ void setSize(int val);
+ }
+
+ public RowTransactional(String id){
+ atomicfields = factory.create();
+
+ this.id=id;
+ atomicfields.setSize(-1);
+ values=new StringKeyHashMap<ValueTransactional>();
+ }
+
+ /**
+ * Returns the number of keys in this row.
+ */
+ public int getKeyCount(){
+ return values.size();
+ }
+
+ public Set keySet(){
+ return values.entrySet();
+ }
+
+ /**
+ * Returns the actual size in bytes this row will take when written to a stream.
+ */
+ public int getSize(){
+ if(atomicfields.getSize()==-1)recalcSize();
+ return atomicfields.getSize();
+ }
+
+ /**
+ * 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{
+ RowTransactional r=(RowTransactional)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,ValueTransactional value){
+ atomicfields.setSize(-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){
+ atomicfields.setSize(-1);
+ values.put(key,new ValueTransactional(value));
+ }
+
+ /**
+ * Stores the given int wrapped in a value object for the given key.
+ */
+ public void put(String key,int value){
+ atomicfields.setSize(-1);
+ values.put(key,new ValueTransactional(value));
+ }
+
+ /**
+ * Stores the given long wrapped in a value object for the given key.
+ */
+ public void put(String key,long value){
+ atomicfields.setSize(-1);
+ values.put(key,new ValueTransactional(value));
+ }
+
+ /**
+ * Stores the given float wrapped in a value object for the given key.
+ */
+ public void put(String key,float value){
+ atomicfields.setSize(-1);
+ values.put(key,new ValueTransactional(value));
+ }
+
+ /**
+ * Stores the given double wrapped in a value object for the given key.
+ */
+ public void put(String key,double value){
+ atomicfields.setSize(-1);
+ values.put(key,new ValueTransactional(value));
+ }
+
+ /**
+ * Stores the given boolean wrapped in a value object for the given key.
+ */
+ public void put(String key,boolean value){
+ atomicfields.setSize(-1);
+ values.put(key,new ValueTransactional(value));
+ }
+
+ /**
+ * Stores the given Date wrapped in a value object for the given key.
+ */
+ public void put(String key,Date value){
+ atomicfields.setSize(-1);
+ values.put(key,new ValueTransactional(value));
+ }
+
+ /**
+ * Returns the value stored for the current key, or a null value (not null) if the key does not exist.
+ */
+ public ValueTransactional get(String key){
+ if(!values.containsKey(key))return new ValueTransactional();
+ return values.get(key.hashCode());
+ }
+
+ /**
+ * 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.hashCode()).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.hashCode()).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.hashCode()).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.hashCode()).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.hashCode()).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.hashCode()).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.hashCode()).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);
+ this.atomicfields.setSize(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<StringKeyHashMap.TEntry<ValueTransactional>> pairs=values.entrySet();
+ out.writeInt(pairs.size());
+ Iterator<StringKeyHashMap.TEntry<ValueTransactional>> it= pairs.iterator();
+ while(it.hasNext()){
+ String key= it.next().getKey();
+ ValueTransactional value= values.get(key);
+ out.writeUTF(key);
+ value.writeToFile(out);
+ }
+
+ long post=out.getFilePointer();
+ int size=(int)(post-pre);
+ this.atomicfields.setSize(size+4);
+ out.writeInt(this.atomicfields.getSize());
+ }
+
+ /**
+ * 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<StringKeyHashMap.TEntry<ValueTransactional>> pairs=values.entrySet();
+ out.writeInt(pairs.size());
+
+ Iterator<StringKeyHashMap.TEntry<ValueTransactional>> it=pairs.iterator();
+ while(it.hasNext()){
+ String key=it.next().getKey();
+ ValueTransactional value=values.get(key);
+ out.writeUTF(key);
+ value.writeToStream(out);
+ }
+ int post=out.size();
+ int size=calcSize(pre,post);
+ this.atomicfields.setSize(size+4);
+ out.writeInt(this.atomicfields.getSize());
+ }
+
+ /**
+ * Reads a full row from the given DataInputStream and returns it.
+ */
+ public static RowTransactional readFromStream(DataInputStream in) throws IOException{
+ String id=in.readUTF();
+ //System.out.println("id " + id);
+ RowTransactional row=new RowTransactional(id);
+ int size=in.readInt();
+ for(int i=0;i<size;i++){
+ String key=in.readUTF();
+ ValueTransactional value=ValueTransactional.readFromStream(in);
+ row.put(key,value);
+ }
+ size=in.readInt();
+ row.atomicfields.setSize(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<StringKeyHashMap.TEntry<ValueTransactional>> it=values.entrySet().iterator();
+ boolean first=true;
+ while(it.hasNext()){
+ if(!first){
+ buf.append(",");
+ }else{
+ first=false;
+ }
+ String key=it.next().getKey();
+ buf.append("\"");
+ buf.append(key);
+ buf.append("\":");
+ ValueTransactional 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<StringKeyHashMap.TEntry<ValueTransactional>> it=values.entrySet().iterator();
+ while(it.hasNext()){
+ String key=it.next().getKey();
+ ValueTransactional 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();
+ }
+
+}
--- /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 dstm2.AtomicSuperClass;
+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 dstm2.atomic;
+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();
+ System.out.println("num=444444444444444444444444 " + num);
+ 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
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import dstm2.AtomicSuperClass;
+import dstm2.atomic;
+import dstm2.Thread;
+import dstm2.factory.Factory;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ *
+ * @author navid
+ */
+public class TableIndexEntryTransactional implements AtomicSuperClass, Comparable<TableIndexEntryTransactional>{
+
+ static Factory<TableIndexEntryTSInf> factory = Thread.makeFactory(TableIndexEntryTSInf.class);
+
+ TableIndexEntryTSInf atomicfields;
+ public @atomic interface TableIndexEntryTSInf{
+ String getId();
+ Integer getLocation();
+ Long getPosition();
+ Integer getSize();
+ Integer getRowsize();
+
+ void setId(String val);
+ void setLocation(Integer val);
+ void setPosition(Long val);
+ void setSize(Integer val);
+ void setRowsize(Integer val);
+ }
+
+
+ public TableIndexEntryTransactional(String id,int rowsize,int location,long position){
+ atomicfields = factory.create();
+
+ this.atomicfields.setId(id);
+ this.atomicfields.setLocation(location);
+ this.atomicfields.setPosition(position);
+ this.atomicfields.setRowsize(rowsize);
+ this.atomicfields.setSize(-1);
+ }
+ public String getId(){
+ return atomicfields.getId();
+ }
+ public void setPosition(long position){
+ this.atomicfields.setPosition(position);
+ }
+ public long getPosition(){
+ return atomicfields.getPosition();
+ }
+ public void setLocation(int location){
+ this.atomicfields.setLocation(location);
+ }
+ public int getLocation(){
+ return atomicfields.getLocation();
+ }
+
+ public int getRowSize(){
+ return atomicfields.getRowsize().intValue();
+ }
+
+ public int compareTo(TableIndexEntryTransactional obj) throws ClassCastException{
+ TableIndexEntryTransactional ent=(TableIndexEntryTransactional)obj;
+ if(atomicfields.getPosition()<ent.atomicfields.getPosition()) return -1;
+ if(atomicfields.getPosition()==ent.atomicfields.getPosition()) return 0;
+ return 1;
+ }
+
+ public boolean equals(Object obj){
+ try{
+ TableIndexEntryTransactional ent=(TableIndexEntryTransactional)obj;
+ if(ent.atomicfields.getLocation()==atomicfields.getLocation()){
+ if(ent.atomicfields.getPosition()==atomicfields.getPosition()){
+ if(ent.atomicfields.getId().equals(atomicfields.getId())){
+ return true;
+ }
+ }
+ }
+ }catch(ClassCastException e){}
+ return false;
+ }
+
+ public int getSize(){
+ if(atomicfields.getSize()<0) calcSize();
+ return atomicfields.getSize().intValue();
+ }
+ public void setSize(int size){
+ this.atomicfields.setSize(size);
+ }
+ private void calcSize(){
+ try{
+ ByteArrayOutputStream bout=new ByteArrayOutputStream();
+ DataOutputStream dout=new DataOutputStream(bout);
+ dout.writeInt(atomicfields.getId().hashCode());
+ dout.writeShort(atomicfields.getId().length());
+ dout.writeChars(atomicfields.getId());
+ dout.writeInt(atomicfields.getRowsize().intValue());
+ dout.writeByte(atomicfields.getLocation());
+ dout.writeLong(atomicfields.getPosition());
+ 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(atomicfields.getId().hashCode());
+ out.writeShort(atomicfields.getId().length());
+ out.writeChars(atomicfields.getId());
+ out.writeInt(atomicfields.getRowsize().intValue());
+ out.writeByte(atomicfields.getLocation());
+ out.writeLong(atomicfields.getPosition());
+ setSize((int)(out.getFilePointer()-pre));
+ }
+ protected void updateData(RandomAccessFile out) throws IOException{
+ long pre=out.getFilePointer();
+ out.skipBytes(4+2+atomicfields.getId().length()*2);
+ out.writeInt(atomicfields.getRowsize().intValue());
+ out.writeByte(atomicfields.getLocation());
+ out.writeLong(atomicfields.getPosition());
+ setSize((int)(out.getFilePointer()-pre));
+ }
+ protected void writeData(DataOutputStream out) throws IOException{
+ out.writeInt(atomicfields.getId().hashCode());
+ out.writeShort(atomicfields.getId().length());
+ out.writeChars(atomicfields.getId());
+ out.writeInt(atomicfields.getRowsize().intValue());
+ out.writeByte(atomicfields.getLocation());
+ out.writeLong(atomicfields.getPosition());
+ }
+ protected static TableIndexEntryTransactional readData(RandomAccessFile in) throws IOException{
+ long pre=in.getFilePointer();
+ in.readInt();
+ //short num=in.readShort();
+ int num=in.readShort();
+ //System.out.println("num= " + num);
+ 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();
+ TableIndexEntryTransactional tmp=new TableIndexEntryTransactional(id,rowsize,location,position);
+ tmp.setSize((int)(in.getFilePointer()-pre));
+ return tmp;
+ }
+
+ protected static TableIndexEntryTransactional 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();
+ TableIndexEntryTransactional tmp=new TableIndexEntryTransactional(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 TableIndexEntryTransactional 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();
+ TableIndexEntryTransactional tmp=new TableIndexEntryTransactional(id,rowsize,location,position);
+ return tmp;
+ }
+ protected static TableIndexEntryTransactional 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();
+ TableIndexEntryTransactional tmp=new TableIndexEntryTransactional(id,rowsize,location,position);
+ return tmp;
+ }
+}
--- /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
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import dstm2.AtomicSuperClass;
+import dstm2.atomic;
+import dstm2.Thread;
+import dstm2.factory.Factory;
+
+/**
+ *
+ * @author navid
+ */
+public class TableIndexNodeTransactional implements AtomicSuperClass{
+
+ //private TableIndexNodeTransactional previous;
+ //private TableIndexEntryTransactional data;
+ //private TableIndexNodeTransactional next;
+ static Factory<TableIndexInodeTSInf> factory = Thread.makeFactory(TableIndexInodeTSInf.class);
+ TableIndexInodeTSInf atomicfields;
+
+ public @atomic interface TableIndexInodeTSInf{
+ TableIndexNodeTransactional getPrevious();
+ TableIndexEntryTransactional getData();
+ TableIndexNodeTransactional getNext();
+
+ void setPrevious(TableIndexNodeTransactional val);
+ void setData(TableIndexEntryTransactional val);
+ void setNext(TableIndexNodeTransactional val);
+ }
+
+ public TableIndexNodeTransactional(){
+ atomicfields = factory.create();
+
+ atomicfields.setPrevious(null);
+ atomicfields.setData(null);
+ atomicfields.setNext(null);
+ }
+
+ public TableIndexNodeTransactional(TableIndexEntryTransactional entry){
+ atomicfields = factory.create();
+
+ atomicfields.setPrevious(null);
+ atomicfields.setData(entry);
+ atomicfields.setNext(null);
+
+ }
+
+ public TableIndexNodeTransactional(TableIndexNodeTransactional prev,TableIndexEntryTransactional entry){
+ atomicfields = factory.create();
+
+ atomicfields.setPrevious(prev);
+ atomicfields.setData(entry);
+ atomicfields.setNext(null);
+ }
+
+ public TableIndexNodeTransactional(TableIndexNodeTransactional prev,TableIndexEntryTransactional entry,TableIndexNodeTransactional nex){
+ atomicfields = factory.create();
+
+ atomicfields.setPrevious(prev);
+ atomicfields.setData(entry);
+ atomicfields.setNext(nex);
+ }
+
+ public TableIndexEntryTransactional getData(){
+ return atomicfields.getData();
+ }
+ public TableIndexNodeTransactional getPrevious(){
+ return atomicfields.getPrevious();
+ }
+ public TableIndexNodeTransactional getNext(){
+ return atomicfields.getNext();
+ }
+ public void setNext(TableIndexNodeTransactional node){
+ atomicfields.setNext(node);
+ }
+ public void setPrevious(TableIndexNodeTransactional node){
+ atomicfields.setPrevious(node);
+ }
+ public void setData(TableIndexEntryTransactional entry){
+ atomicfields.setData(entry);
+ }
+ public void remove(){
+ if(atomicfields.getPrevious()!=null){
+ atomicfields.getPrevious().setNext(atomicfields.getNext());
+ }
+ if(atomicfields.getNext()!=null){
+ atomicfields.getNext().setPrevious(atomicfields.getPrevious());
+ }
+ }
+}
--- /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();
+ // System.out.println("si " + size);
+ // System.out.println("next " + next);
+ // System.out.println("lower " + lower);
+ // System.out.println("offset " + offset);
+ // System.out.println("endhash " + endhash);
+ if(offset>0)starthash=file.readInt();
+ // System.out.println("here tav;eindepage");
+
+
+ }
+
+ 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();
+ System.out.println(Thread.currentThread() + " " +offset + " " + pre);
+ 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{
+ System.out.println("sacn index");
+ 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){
+ System.out.println("neddddxtex " + next);
+ TableIndexEntry entry=TableIndexEntry.lookForData(id,file);
+ if(entry!=null)return entry;
+ }
+ System.out.println("neddddxt " + next);
+ if(next==-1)return null;
+
+ if(nextpage==null){
+ System.out.println("next " + next);
+ 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 dstm2.AtomicSuperClass;
+import dstm2.atomic;
+import dstm2.Thread;
+import dstm2.factory.Factory;
+import java.io.*;
+import java.util.*;
+
+public class TableIndexPageTransactional implements AtomicSuperClass{
+ static Factory<TableIndexPageTSInf> factory = Thread.makeFactory(TableIndexPageTSInf.class);
+
+ /*static*/ TableIndexPageTSInf atomicfields = null;
+ private final static int BASEOFFSET=4+8+8+4+4;
+ private RandomAccessFile file=null;
+
+
+
+ public @atomic interface TableIndexPageTSInf{
+ Long getLocation();
+ Integer getSize();
+ Long getNext();
+ Long getLower();
+ Integer getOffset();
+ Integer getStarthash();
+ Integer getEndhash();
+ Boolean getFirst();
+ TableIndexPageTransactional getNextpage();
+ TableIndexPageTransactional getLowerpage();
+ PagedIndexTransactional getIndex();
+
+
+ void setLowerpage(TableIndexPageTransactional lowerpage);
+ void setNextpage(TableIndexPageTransactional nextpage);
+ void setFirst(Boolean val);
+ void setEndhash(Integer val);
+ void setStarthash(Integer val);
+ void setOffset(Integer offset);
+ void setNext(Long next);
+ void setSize(Integer size);
+ void setLocation(Long location);
+ void setLower(Long val);
+ void setIndex(PagedIndexTransactional val);
+ }
+
+
+
+ public TableIndexPageTransactional(PagedIndexTransactional index,RandomAccessFile file) throws IOException{
+ this.file=file;
+ atomicfields = factory.create();
+ this.atomicfields.setIndex(index);
+ this.atomicfields.setFirst(false);
+ this.atomicfields.setLocation(file.getFilePointer());
+ // System.out.println(file.getFilePointer());
+ this.atomicfields.setSize(file.readInt());
+ // System.out.println(file.getFilePointer());
+ this.atomicfields.setNext(file.readLong());
+ // System.out.println(file.getFilePointer());
+ this.atomicfields.setLower(file.readLong());
+ // System.out.println(file.getFilePointer());
+ // System.out.println(file.getFilePointer());
+ this.atomicfields.setOffset(file.readInt());
+ // System.out.println(file.getFilePointer());
+ this.atomicfields.setEndhash(file.readInt());
+ // System.out.println("size " + atomicfields.getSize());
+ System.out.println("next " + atomicfields.getNext());
+ System.out.println("lower " + atomicfields.getLower());
+ System.out.println("offset " + atomicfields.getOffset());
+ System.out.println("endhash " + atomicfields.getEndhash());
+ if(this.atomicfields.getOffset()>0)
+ this.atomicfields.setStarthash(file.readInt());
+ else
+ this.atomicfields.setStarthash(-1);
+ }
+
+ public static TableIndexPageTransactional createNewPage(PagedIndexTransactional index,RandomAccessFile file,int size) throws IOException{
+
+ long pre=file.length();
+
+ file.setLength(file.length()+size+BASEOFFSET);
+ file.seek(pre);
+
+ // System.out.println("pointer2 " + file.getFilePointer());
+ file.writeInt(size);
+
+ // System.out.println("pointer2 " + file.getFilePointer());
+ file.writeLong(-1l);
+ // System.out.println("pointer2 " + file.getFilePointer());
+ file.writeLong(-1l);
+ // System.out.println("pointer2 " + file.getFilePointer());
+ file.writeInt(0);
+ // System.out.println("pointer2 " + file.getFilePointer());
+ file.writeInt(-1);
+ file.seek(pre);
+ // file.readInt();
+ // file.readLong();
+ // file.readLong();
+ // file.readInt();
+ // file.readInt();
+ // file.seek(pre);
+
+ //index.atomicfields.setStat_create_page((long)2);
+ index.atomicfields.setStat_create_page(index.atomicfields.getStat_create_page()+1);
+ return new TableIndexPageTransactional(index,file);
+ }
+
+ public void setFirst(){
+ this.atomicfields.setFirst(true);
+ }
+
+ public long getLocation(){
+ return atomicfields.getLocation();
+ }
+ public long getEndLocation(){
+ return this.atomicfields.getLocation()+atomicfields.getSize()+BASEOFFSET;
+ }
+
+ public String toString(){
+ StringBuffer buf=new StringBuffer();
+ buf.append("{\n");
+ buf.append(" location "+this.atomicfields.getLocation()+"\n");
+ buf.append(" size "+this.atomicfields.getSize()+"\n");
+ buf.append(" next "+this.atomicfields.getNext()+"\n");
+ buf.append(" lower "+this.atomicfields.getLower()+"\n");
+ buf.append(" offset "+this.atomicfields.getOffset()+"\n");
+ buf.append(" starthash "+this.atomicfields.getStarthash()+"\n");
+ buf.append(" endhash "+this.atomicfields.getEndhash()+"\n");
+ buf.append("}\n");
+ return buf.toString();
+ }
+
+ private void updateMeta() throws IOException{
+ file.seek(this.atomicfields.getLocation());
+ file.writeInt(this.atomicfields.getSize());
+ file.writeLong(this.atomicfields.getNext());
+ file.writeLong(this.atomicfields.getLower());
+ file.writeInt(this.atomicfields.getOffset());
+ file.writeInt(this.atomicfields.getEndhash());
+ }
+
+ public void addEntriesToList(List<TableIndexEntryTransactional> lst) throws IOException{
+ if(this.atomicfields.getLower()>-1){
+ if(this.atomicfields.getLowerpage()==null){
+ file.seek(this.atomicfields.getLower());
+ this.atomicfields.setLowerpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
+ }
+ this.atomicfields.getLowerpage().addEntriesToList(lst);
+ }
+ if(this.atomicfields.getNext()>-1){
+ if(this.atomicfields.getNextpage()==null){
+ file.seek(this.atomicfields.getNext());
+ this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
+ }
+ this.atomicfields.getNextpage().addEntriesToList(lst);
+ }
+ file.seek(this.atomicfields.getLocation()+BASEOFFSET);
+ long pre=file.getFilePointer();
+ // System.out.println(Thread.currentThread() + " " +this.atomicfields.getOffset() + " " + pre);
+ while(file.getFilePointer()<pre+this.atomicfields.getOffset()){
+
+ TableIndexEntryTransactional entry=TableIndexEntryTransactional.readData(file);
+ if(entry!=null){
+ if(entry.getLocation()!=TableTransactional.DELETE)lst.add(entry);
+ }
+ }
+ }
+
+ public TableIndexEntryTransactional scanIndex(String id,int hashcode) throws IOException{
+ if(!atomicfields.getFirst()){
+ if(hashcode<atomicfields.getStarthash()){
+ if(atomicfields.getLower()==-1) return null;
+ if(this.atomicfields.getLowerpage()==null){
+ file.seek(this.atomicfields.getLower());
+ this.atomicfields.setLowerpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
+ }
+ atomicfields.getIndex().atomicfields.setStat_page_branch(atomicfields.getIndex().atomicfields.getStat_page_branch()+1);
+ return this.atomicfields.getLowerpage().scanIndex(id,hashcode);
+ }
+ }
+ if(hashcode>this.atomicfields.getEndhash()){
+ if(this.atomicfields.getNext()==-1)return null;
+ if(this.atomicfields.getNextpage()==null){
+ file.seek(this.atomicfields.getNext());
+ this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
+ }
+ atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
+ return this.atomicfields.getNextpage().scanIndex(id,hashcode);
+ }
+ file.seek(this.atomicfields.getLocation()+BASEOFFSET);
+ long pre=file.getFilePointer();
+ while(file.getFilePointer()<pre+this.atomicfields.getOffset()){
+ //System.out.println("neddddxtex " + atomicfields.getNext());
+ TableIndexEntryTransactional entry=TableIndexEntryTransactional.lookForData(id,file);
+ if(entry!=null)return entry;
+ }
+ if(this.atomicfields.getNext()==-1)return null;
+ if(this.atomicfields.getNextpage()==null){
+ file.seek(this.atomicfields.getNext());
+ this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
+ }
+ atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
+ return this.atomicfields.getNextpage().scanIndex(id,hashcode);
+ }
+ protected long getOffset(String id,int hashcode) throws IOException{
+ if(!this.atomicfields.getFirst()){
+ if(hashcode<this.atomicfields.getStarthash()){
+ if(this.atomicfields.getLower()==-1)return -1;
+ if(this.atomicfields.getLowerpage()==null){
+ file.seek(atomicfields.getLower());
+ this.atomicfields.setLowerpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
+ }
+ atomicfields.getIndex().atomicfields.setStat_page_branch(atomicfields.getIndex().atomicfields.getStat_page_branch()+1);
+ return this.atomicfields.getLowerpage().getOffset(id,hashcode);
+ }
+ }
+ if(hashcode>this.atomicfields.getEndhash()){
+ if(this.atomicfields.getNext()==-1)return -1;
+ if(this.atomicfields.getNextpage()==null){
+ file.seek(this.atomicfields.getNext());
+ this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
+ }
+ atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
+ return this.atomicfields.getNextpage().getOffset(id,hashcode);
+ }
+ file.seek(this.atomicfields.getLocation()+BASEOFFSET);
+ long pre=file.getFilePointer();
+ while(file.getFilePointer()<pre+this.atomicfields.getOffset()){
+ long prescan=file.getFilePointer();
+ TableIndexEntryTransactional entry=TableIndexEntryTransactional.lookForData(id,file);
+ if(entry!=null)return prescan;
+ }
+ if(this.atomicfields.getNext()==-1)return -1;
+ if(this.atomicfields.getNextpage()==null){
+ file.seek(this.atomicfields.getNext());
+ this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
+ }
+ atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
+ return this.atomicfields.getNextpage().getOffset(id,hashcode);
+ }
+
+ protected TableIndexPageTransactional getFirstFreePage(String id,int hashcode) throws IOException{
+ // Is this an empty page?
+ if(this.atomicfields.getOffset()==0){
+ return this;
+ }
+ // Is this hash lower than the starthash
+ if(!this.atomicfields.getFirst()){
+ if(hashcode<this.atomicfields.getStarthash()){
+ if(this.atomicfields.getLower()==-1){
+ this.atomicfields.setLower(file.length());
+ updateMeta();
+ return createNewPage(this.atomicfields.getIndex(),file,PagedIndexTransactional.PAGESIZE);
+ }
+ if(this.atomicfields.getLowerpage()==null){
+ file.seek(this.atomicfields.getLower());
+ this.atomicfields.setLowerpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
+ }
+ atomicfields.getIndex().atomicfields.setStat_page_branch(atomicfields.getIndex().atomicfields.getStat_page_branch()+1);
+ return this.atomicfields.getLowerpage().getFirstFreePage(id,hashcode);
+ }
+ }
+ // Do we have space in this page
+ if(this.atomicfields.getSize()-this.atomicfields.getOffset()>id.length()*2+4+4+8+1+2)return this;
+ // Check next
+ if(this.atomicfields.getNext()==-1){
+ this.atomicfields.setNext(file.length());
+ updateMeta();
+ return createNewPage(this.atomicfields.getIndex(),file,PagedIndexTransactional.PAGESIZE);
+ }
+ if(this.atomicfields.getNextpage()==null){
+ file.seek(this.atomicfields.getNext());
+ this.atomicfields.setNextpage(new TableIndexPageTransactional(this.atomicfields.getIndex(),file));
+ }
+ atomicfields.getIndex().atomicfields.setStat_page_next(atomicfields.getIndex().atomicfields.getStat_page_next()+1);
+ return this.atomicfields.getNextpage().getFirstFreePage(id,hashcode);
+ }
+
+ public void addEntry(String id,int rowsize,int location,long position) throws IOException{
+ if(atomicfields.getOffset()==0)this.atomicfields.setStarthash(id.hashCode());
+ file.seek(this.atomicfields.getLocation()+BASEOFFSET+this.atomicfields.getOffset());
+ TableIndexEntryTransactional entry=new TableIndexEntryTransactional(id,rowsize,location,position);
+ entry.writeData(file);
+ this.atomicfields.setOffset(this.atomicfields.getOffset()+entry.getSize());
+ if(id.hashCode()>this.atomicfields.getEndhash()) this.atomicfields.setEndhash(id.hashCode());
+ updateMeta();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import dstm2.AtomicSuperClass;
+import java.util.*;
+import java.io.*;
+
+public interface TableIndexTransactional extends AtomicSuperClass{
+ public Hashtable<String,Long> readStatistics();
+ public void updateEntry(String id,int rowsize,int location,long position) throws IOException;
+ public void updateEntryTransactional(String id,int rowsize,int location,long position) throws IOException;
+ public void addEntry(String id,int rowsize,int location,long position) throws IOException;
+ public TableIndexEntryTransactional scanIndex(String id) throws IOException;
+ public TableIndexEntryTransactional scanIndexTransactional(String id) throws IOException;
+ public List<TableIndexEntryTransactional> scanIndex(List<String> rows) throws IOException;
+ public List<TableIndexEntryTransactional> scanIndex() throws IOException;
+ public void close();
+}
\ No newline at end of file
--- /dev/null
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+/**
+ *
+ * @author navid
+ */
+/*
+ * 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.
+ */
+
+
+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 TableTransactional{
+ // 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(RowTransactional 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(RowTransactional row) throws IOException;
+
+ /**
+ * Updates a row stored in this table.
+ */
+ public void updateRow(RowTransactional 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(RowTransactional row) throws IOException;
+
+ /**
+ * Returns a tuplestream containing the given list of rows
+ */
+ public TupleStreamTransactional getRows(List<String> rows) throws IOException;
+
+ /**
+ * Returns a tuplestream containing the rows matching the given rowmatcher
+ */
+ public TupleStreamTransactional getRows(RowMatcherTransactional matcher) throws IOException;
+
+ /**
+ * Returns a tuplestream containing those rows in the given list that matches the given RowMatcher
+ */
+ public TupleStreamTransactional getRows(List<String> rows,RowMatcherTransactional matcher) throws IOException;
+
+ /**
+ * Returns a tuplestream of all rows in this table.
+ */
+ public TupleStreamTransactional 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 RowTransactional 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.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.io.*;
+import java.util.*;
+
+public class TupleStreamMergerTransactional extends TupleStreamTransactional{
+ private List<TupleStreamTransactional> streams;
+ private TupleStreamTransactional current=null;
+ private RowTransactional next=null;
+
+ public TupleStreamMergerTransactional(){
+ streams=new ArrayList<TupleStreamTransactional>();
+ }
+
+ public void addStream(TupleStreamTransactional 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 RowTransactional next() throws IOException{
+ if(next==null)hasNext();
+ RowTransactional tmp=next;
+ next=null;
+ return tmp;
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import java.io.IOException;
+
+/**
+ *
+ * @author navid
+ */
+public abstract class TupleStreamTransactional {
+ public abstract boolean hasNext() throws IOException;
+ public abstract RowTransactional next() throws IOException;
+}
--- /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
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+import dstm2.AtomicByteArray;
+import dstm2.AtomicSuperClass;
+import dstm2.atomic;
+import dstm2.factory.Factory;
+import java.util.*;
+import java.io.*;
+import dstm2.Thread;
+
+/**
+ *
+ * @author navid
+ */
+public class ValueTransactional implements AtomicSuperClass{
+
+ ValueTSInf atomicfields;
+ static Factory<ValueTSInf> factory = Thread.makeFactory(ValueTSInf.class);
+
+ public @atomic interface ValueTSInf{
+ Byte getType();
+ String getStr_value();
+ Long getInt_value();
+ Double getFloat_value();
+ AtomicByteArray getBinary();
+
+ void setType(Byte val);
+ void setStr_value(String val);
+ void setInt_value(Long val);
+ void setFloat_value(Double val);
+ void setBinary(AtomicByteArray bytes);
+ }
+
+
+ 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 atomicfields.getType();
+ }
+
+ /**
+ * Returns the name this value's type.
+ */
+ public String getTypeName(){
+ switch(atomicfields.getType()){
+ 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(atomicfields.getType()){
+ case STRING : hash+=atomicfields.getStr_value().hashCode();
+ case INT : hash+=atomicfields.getInt_value();
+ case LONG : hash+=atomicfields.getInt_value();
+ case FLOAT : hash+=atomicfields.getFloat_value();
+ case DOUBLE : hash+=atomicfields.getFloat_value();
+ case BOOLEAN : hash+=atomicfields.getInt_value();
+ case TIMESTAMP : hash+=atomicfields.getInt_value();
+ case BINARY : hash+=atomicfields.getBinary().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 atomicfields.getType()==NULL;
+ }
+
+ /**
+ * Returns -1, 0 or 1 if this value is smaller, equal or larger than the value given as a parameter.
+ */
+ public int compareTo(ValueTransactional value){
+ if(atomicfields.getType()==STRING){
+ return atomicfields.getStr_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(ValueTransactional value){
+ switch(atomicfields.getType()){
+ 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(ValueTransactional value){
+ switch(atomicfields.getType()){
+ 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(ValueTransactional 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(ValueTransactional 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(ValueTransactional 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{
+ ValueTransactional val=(ValueTransactional)obj;
+ if(val.atomicfields.getType()==atomicfields.getType()){
+ switch(atomicfields.getType()){
+ case NULL : return true;
+ case STRING : return atomicfields.getStr_value().equals(val.atomicfields.getStr_value());
+ case INT : return atomicfields.getInt_value()==atomicfields.getInt_value();
+ case LONG : return atomicfields.getInt_value()==atomicfields.getInt_value();
+ case FLOAT : return atomicfields.getFloat_value()==atomicfields.getFloat_value();
+ case DOUBLE : return atomicfields.getFloat_value()==atomicfields.getFloat_value();
+ case BOOLEAN : return atomicfields.getInt_value()==atomicfields.getInt_value();
+ case TIMESTAMP : return atomicfields.getInt_value()==atomicfields.getInt_value();
+ case BINARY : if(atomicfields.getBinary().length()==val.atomicfields.getBinary().length()){
+ for(int i=0;i<atomicfields.getBinary().length();i++){
+ if(atomicfields.getBinary().get(i)!=val.atomicfields.getBinary().get(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(atomicfields.getType()){
+ case STRING : return "<value name=\""+key+"\" type=\"string\">"+atomicfields.getStr_value()+"</value>";
+ case INT : return "<value name=\""+key+"\" type=\"int\">"+atomicfields.getInt_value()+"</value>";
+ case LONG : return "<value name=\""+key+"\" type=\"long\">"+atomicfields.getInt_value()+"</value>";
+ case FLOAT : return "<value name=\""+key+"\" type=\"float\">"+atomicfields.getFloat_value()+"</value>";
+ case DOUBLE : return "<value name=\""+key+"\" type=\"double\">"+atomicfields.getFloat_value()+"</value>";
+ case BOOLEAN : if(atomicfields.getInt_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(atomicfields.getInt_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(atomicfields.getType()){
+ case STRING : return "<value type=\"string\">"+atomicfields.getStr_value()+"</value>";
+ case INT : return "<value type=\"int\">"+atomicfields.getInt_value()+"</value>";
+ case LONG : return "<value type=\"long\">"+atomicfields.getInt_value()+"</value>";
+ case FLOAT : return "<value type=\"float\">"+atomicfields.getFloat_value()+"</value>";
+ case DOUBLE : return "<value type=\"double\">"+atomicfields.getFloat_value()+"</value>";
+ case BOOLEAN : if(atomicfields.getInt_value()==1){
+ return "<value type=\"boolean\">TRUE</value>";
+ }else{
+ return "<value type=\"boolean\">FALSE</value>";
+ }
+ case TIMESTAMP : return "<value type=\"timestamp\">"+new Date(atomicfields.getInt_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(atomicfields.getType()){
+ case STRING : return atomicfields.getStr_value();
+ case INT : return ""+atomicfields.getInt_value();
+ case LONG : return ""+atomicfields.getInt_value();
+ case FLOAT : return ""+atomicfields.getFloat_value();
+ case DOUBLE : return ""+atomicfields.getFloat_value();
+ case BOOLEAN : if(atomicfields.getInt_value()==1){
+ return "TRUE";
+ }else{
+ return "FALSE";
+ }
+ case TIMESTAMP : return new Date(atomicfields.getInt_value()).toString();
+ case BINARY : StringBuffer buf=new StringBuffer();
+ for(int i=0;i<atomicfields.getBinary().length();i++){
+ byte b=atomicfields.getBinary().get(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(atomicfields.getType()){
+ case STRING : return Integer.parseInt(atomicfields.getStr_value());
+ case INT : return atomicfields.getInt_value().intValue();
+ case LONG : return (int)atomicfields.getInt_value().intValue();
+ case FLOAT : return (int)atomicfields.getFloat_value().intValue();
+ case DOUBLE : return (int)atomicfields.getFloat_value().intValue();
+ case BOOLEAN : return (int)atomicfields.getInt_value().intValue();
+ case TIMESTAMP : return (int)(atomicfields.getInt_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(atomicfields.getType()){
+ case STRING : return Long.parseLong(atomicfields.getStr_value());
+ case INT : return atomicfields.getInt_value();
+ case LONG : return atomicfields.getInt_value();
+ case FLOAT : return (long)atomicfields.getFloat_value().longValue();
+ case DOUBLE : return (long)atomicfields.getFloat_value().longValue();
+ case BOOLEAN : return atomicfields.getInt_value();
+ case TIMESTAMP : return atomicfields.getInt_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(atomicfields.getType()){
+ case STRING : return Float.parseFloat(atomicfields.getStr_value());
+ case INT : return (float)atomicfields.getInt_value().floatValue();
+ case LONG : return (float)atomicfields.getInt_value().floatValue();
+ case FLOAT : return (float)atomicfields.getFloat_value().floatValue();
+ case DOUBLE : return (float)atomicfields.getFloat_value().floatValue();
+ case BOOLEAN : return (float)atomicfields.getInt_value().floatValue();
+ case TIMESTAMP : return (float)(atomicfields.getInt_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(atomicfields.getType()){
+ case STRING : return Double.parseDouble(atomicfields.getStr_value());
+ case INT : return (double)atomicfields.getInt_value();
+ case LONG : return (double)atomicfields.getInt_value();
+ case FLOAT : return (double)atomicfields.getFloat_value();
+ case DOUBLE : return (double)atomicfields.getFloat_value();
+ case BOOLEAN : return (double)atomicfields.getInt_value();
+ case TIMESTAMP : return (double)(atomicfields.getInt_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(atomicfields.getType()){
+ case STRING : if(atomicfields.getStr_value().toLowerCase().trim().equals("true"))return true;
+ if(atomicfields.getStr_value().trim().equals("1"))return true;
+ if(atomicfields.getStr_value().toLowerCase().trim().equals("t"))return true;
+ if(atomicfields.getStr_value().toLowerCase().trim().equals("yes"))return true;
+ if(atomicfields.getStr_value().toLowerCase().trim().equals("on"))return true;
+ case INT : if(atomicfields.getInt_value()==1)return true;
+ case LONG : if(atomicfields.getInt_value()==1)return true;
+ case FLOAT : if(atomicfields.getFloat_value()==1.0f)return true;
+ case DOUBLE : if(atomicfields.getFloat_value()==1.0)return true;
+ case BOOLEAN : if(atomicfields.getInt_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(atomicfields.getType()){
+ case INT : return new Date(atomicfields.getInt_value()*1000l);
+ case LONG : return new Date(atomicfields.getInt_value());
+ case FLOAT : return new Date((long)(atomicfields.getFloat_value()*1000l));
+ case DOUBLE : return new Date((long)atomicfields.getFloat_value().longValue());
+ case TIMESTAMP : return new Date(atomicfields.getInt_value());
+ }
+ }catch(Exception e){}
+ return new Date(0);
+ }
+
+ public AtomicByteArray getBinary(){
+ switch(atomicfields.getType()){
+ case BINARY : return atomicfields.getBinary();
+ }
+ 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(atomicfields.getType());
+ switch(atomicfields.getType()){
+ case STRING : out.writeInt(atomicfields.getStr_value().length());
+ for(int i=0;i<atomicfields.getStr_value().length();i++){
+ out.writeChar(atomicfields.getStr_value().charAt(i));
+ }
+ break;
+ case INT : out.writeInt((int)atomicfields.getInt_value().intValue());
+ break;
+ case LONG : out.writeLong(atomicfields.getInt_value());
+ break;
+ case FLOAT : out.writeFloat((float)atomicfields.getFloat_value().intValue());
+ break;
+ case DOUBLE : out.writeDouble(atomicfields.getFloat_value());
+ break;
+ case BOOLEAN: out.writeBoolean(atomicfields.getInt_value()==1);
+ break;
+ case TIMESTAMP: out.writeLong(atomicfields.getInt_value());
+ break;
+ case BINARY : out.writeInt(atomicfields.getBinary().length());
+ for (int i=0; i<atomicfields.getBinary().length(); i++)
+ out.write(atomicfields.getBinary().get(i));
+ 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(RandomAccessFile out) throws IOException{
+ out.writeByte(atomicfields.getType());
+ switch(atomicfields.getType()){
+ case STRING : out.writeInt(atomicfields.getStr_value().length());
+ for(int i=0;i<atomicfields.getStr_value().length();i++){
+ out.writeChar(atomicfields.getStr_value().charAt(i));
+ }
+ break;
+ case INT : out.writeInt((int)atomicfields.getInt_value().intValue());
+ break;
+ case LONG : out.writeLong(atomicfields.getInt_value());
+ break;
+ case FLOAT : out.writeFloat((float)atomicfields.getFloat_value().intValue());
+ break;
+ case DOUBLE : out.writeDouble(atomicfields.getFloat_value());
+ break;
+ case BOOLEAN: out.writeBoolean(atomicfields.getInt_value()==1);
+ break;
+ case TIMESTAMP: out.writeLong(atomicfields.getInt_value());
+ break;
+ case BINARY : out.writeInt(atomicfields.getBinary().length());
+ for (int i=0; i<atomicfields.getBinary().length(); i++)
+ out.writeByte(atomicfields.getBinary().get(i));
+
+ }
+ }
+
+ /**
+ * 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 ValueTransactional 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 ValueTransactional(buf.toString());
+ case INT : return new ValueTransactional(in.readInt());
+ case LONG : return new ValueTransactional(in.readLong());
+ case FLOAT : return new ValueTransactional(in.readFloat());
+ case DOUBLE : return new ValueTransactional(in.readDouble());
+ case BOOLEAN: return new ValueTransactional(in.readBoolean());
+ case TIMESTAMP: return new ValueTransactional(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 ValueTransactional(abuf);
+
+ }
+ return new ValueTransactional();
+ }
+
+ /* public static ValueTransactional readFromStream(TransactionalFile 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 ValueTransactional(buf.toString());
+ case INT : return new ValueTransactional(in.readInt());
+ case LONG : return new ValueTransactional(in.readLong());
+ case FLOAT : return new ValueTransactional(in.readFloat());
+ case DOUBLE : return new ValueTransactional(in.readDouble());
+ case BOOLEAN: return new ValueTransactional(in.readBoolean());
+ case TIMESTAMP: return new ValueTransactional(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 ValueTransactional(abuf);
+
+ }
+ return new ValueTransactional();
+ }*/
+
+ /**
+ * Initializes this Value with the given String.
+ *
+ * @param val the value this Value object should represent
+ */
+ public ValueTransactional(String val){
+ this();
+ atomicfields.setStr_value(val);
+ atomicfields.setType((byte)STRING);
+ }
+
+ public ValueTransactional(byte[] val){
+ this();
+ atomicfields.setBinary(new AtomicByteArray(Byte.class, val.length));
+ for (int i=0; i<val.length; i++)
+ atomicfields.getBinary().set(i, val[i]);
+
+ atomicfields.setType((byte)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 ValueTransactional(Date val){
+ atomicfields.setInt_value(val.getTime());
+ atomicfields.setType((byte)TIMESTAMP);
+ }
+
+ /**
+ * Initializes this Value as null.
+ */
+ public ValueTransactional(){
+ atomicfields = factory.create();
+ atomicfields.setStr_value(null);
+ atomicfields.setInt_value(Long.valueOf(0));
+ atomicfields.setFloat_value(0.0);
+ atomicfields.setBinary(new AtomicByteArray(Byte.class, NULL));
+ atomicfields.setType((byte)NULL);
+ }
+
+ /**
+ * Initializes this Value with the given int.
+ *
+ * @param val the value this Value object should represent
+ */
+ public ValueTransactional(int val){
+ this();
+ atomicfields.setInt_value(Long.valueOf(val));
+ atomicfields.setType((byte)INT);
+ }
+
+ /**
+ * Initializes this Value with the given long.
+ *
+ * @param val the value this Value object should represent
+ */
+ public ValueTransactional(long val){
+ this();
+ atomicfields.setInt_value(val);
+ atomicfields.setType((byte)LONG);
+ }
+
+ /**
+ * Initializes this Value with the given float.
+ *
+ * @param val the value this Value object should represent
+ */
+ public ValueTransactional(float val){
+ this();
+ atomicfields.setFloat_value(Double.valueOf(val));
+ atomicfields.setType((byte)FLOAT);
+ }
+
+ /**
+ * Initializes this Value with the given double.
+ *
+ * @param val the value this Value object should represent
+ */
+ public ValueTransactional(double val){
+ this();
+ atomicfields.setFloat_value(val);
+ atomicfields.setType((byte)DOUBLE);
+ }
+
+ /**
+ * Initializes this Value with the given boolean.
+ *
+ * @param val the value this Value object should represent
+ */
+ public ValueTransactional(boolean val){
+ this();
+ if(val){
+ atomicfields.setInt_value(Long.valueOf(1));
+ }else{
+ atomicfields.setInt_value(Long.valueOf(0));
+ }
+ atomicfields.setType((byte)BOOLEAN);
+ }
+
+
+
+}
--- /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 java.util.*;
+import java.io.*;
+import com.solidosystems.tuplesoup.core.*;
+
+public class RowBufferTransactional extends TupleStreamTransactional{
+ private int CACHESIZE=32768;
+ private int cacheusage=0;
+
+ private int mempointer=0;
+ private boolean diskused=false;
+
+ private List<RowTransactional> membuffer;
+ private String diskbuffer;
+ private DataOutputStream out;
+ private DataInputStream in;
+
+ private RowTransactional next=null;
+
+ public RowBufferTransactional(String filename){
+ membuffer=new ArrayList<RowTransactional>();
+ diskbuffer=filename;
+ out=null;
+ in=null;
+ }
+
+ public void setCacheSize(int size){
+ CACHESIZE=size;
+ }
+ public int getCacheSize(){
+ return CACHESIZE;
+ }
+
+ public void addRow(RowTransactional 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=RowTransactional.readFromStream(in);
+ }catch(EOFException e){
+ next=null;
+ }
+ }else next=null;
+ }
+ }
+
+ public boolean hasNext() throws IOException{
+ if(next!=null)return true;
+ return false;
+ }
+
+ public RowTransactional next() throws IOException{
+ try{
+ if(next!=null){
+ RowTransactional 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 dstm2.Init;
+ import java.util.*;
+ import java.io.*;
+
+
+public class OrigParralelPerformanceTest extends BasicTest implements Runnable{
+
+ long writetime;
+ long readtime;
+ long randomtime;
+
+ public OrigParralelPerformanceTest(){
+ String path="/home/navid/Volumes/My Book/test/";
+ try{
+ //int records=50000;
+ int records=5;
+ for(int i=1;i<2/*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 table=new DualFileTable("Performance-test",path,Table.PAGED);
+ //TableTransactional table=new DualFileTableTransactional("Performance-test",path,TableTransactional.PAGED);
+ benchmark(table,5,(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 HashedTableTransactional("Performance-test",path,TableTransactional.PAGED);
+ // 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){
+ Init.init();
+ new OrigParralelPerformanceTest();
+ }
+
+ 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 OrigParralelThread(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++){
+ // RowTransactional row=new RowTransactional(id+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();
+ //TupleStreamTransactional 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));
+ System.out.println(row);
+ //RowTransactional 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 OrigParralelThread implements Runnable{
+ String id;
+ int records;
+ OrigParralelPerformanceTest app;
+ Table table;
+ //TableTransactional table;
+
+ public OrigParralelThread(OrigParralelPerformanceTest 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;
+ 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 dstm2.Init;
+ import java.util.*;
+ import java.io.*;
+
+
+public class ParallelPerformanceTest extends BasicTest implements Runnable{
+
+ long writetime;
+ long readtime;
+ long randomtime;
+
+ public ParallelPerformanceTest(){
+ String path="/home/navid/Volumes/My Book/test/";
+ try{
+ //int records=10;
+ int records=5;
+ for(int i=1;i<2;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 table=new DualFileTable("Performance-test",path,Table.PAGED);
+ TableTransactional table=new DualFileTableTransactional("Performance-test",path,TableTransactional.PAGED);
+ benchmark(table,5,(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 HashedTableTransactional("Performance-test",path,TableTransactional.PAGED);
+ // table=new HashedTableTransactional("Performance-test",path,TableTransactional.PAGED);
+ // benchmark(table,i,(records/i));
+ // table.close();
+ // table.deleteFiles();*/
+ }
+
+
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+ public static void main(String[] args){
+ Init.init();
+ new ParallelPerformanceTest();
+ }
+
+ public void benchmark(TableTransactional table/*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(TableTransactional table,int records, String id) throws IOException{
+ long pre=System.currentTimeMillis();
+ for(int i=0;i<records;i++){
+ RowTransactional row=new RowTransactional(id+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 ValueTransactional(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(TableTransactional table,int records, String id) throws IOException{
+ long pre=System.currentTimeMillis();
+ //TupleStream stream=table.getRows();
+ TupleStreamTransactional stream=table.getRows();
+ while(stream.hasNext()){
+ stream.next();
+ // System.out.println(stream);
+ }
+ long post=System.currentTimeMillis();
+ return post-pre;
+ }
+ public long benchmarkLargeRandomRead(TableTransactional table/*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));
+ RowTransactional row=table.getRow(id+(int)(Math.random()*records));
+ System.out.println("row " + row);
+ }
+ 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;
+ TableTransactional table;
+
+ public ParallelThread(ParallelPerformanceTest app,TableTransactional table/*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