Package dovetaildb.bagindex

Source Code of dovetaildb.bagindex.TrieBagIndex

package dovetaildb.bagindex;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.LongBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import dovetaildb.fileaccessor.MappedFile;
import dovetaildb.fileaccessor.OffsetValueFilePair;
import dovetaildb.fileaccessor.PagedFile;
import dovetaildb.scan.AbstractScanner;
import dovetaildb.scan.IntegerScanner;
import dovetaildb.scan.Scanner;
import dovetaildb.scan.ScannerUtil;
import dovetaildb.score.Score;
import dovetaildb.score.Scorer;
import dovetaildb.store.BytesInterface;
import dovetaildb.store.ChannelBasedMappedFile;
import dovetaildb.store.ChunkedMemoryMappedFile;
import dovetaildb.store.MappedBytesInterface;
import dovetaildb.store.VarPosition;
import dovetaildb.util.Pair;
import dovetaildb.util.Util;
import dovetaildb.util.VIntScanner;

public class TrieBagIndex extends BagIndex {

  /**
   * Pages:
   * Trie page (link up + summary list + link complete list + 256 links down)
   * Single value posting list page (link up + single value + compressed doc id list) -- NOT USED
   * Multi value posting list page (link prev:4 + link next:4 + compressed doc id list + value list) (as much as fits on one page)
   *   First offset is the complete initial doc number, subsequent offsets are increments with the low bit reserved for whether the value is different than the previous.
   *   When low bit is not set, a value pointer VLong follows, the low bit of which indicates whether the value is inline.
   *   When this low bit is not set, the value is considered an offset into the values file and a Vlong for the value length follows.
   * ID terms are suffixed with pointers to remainder of data -> (compressed value page link & offset) list
   * Deletions: add a *del:<docid>*(<txn>) field
   *
   */
 
  PagedFile pages;
  BytesInterface pageBi;
  protected final int pageSize;
  protected final int overflowThreshold;
  protected final int minRecsPerPage;

  protected BytesInterface maxDocIdFile;
  long maxDocId;
 
  /** Simple 4 bytes per docId, indexed from zero, representing an unsigned pointer into the docFields file */
  protected MappedBytesInterface docIdToDoc;
 
  /** Each doc is a list of VInts, each doc is an ordered list of value pointers, low bit indicates
   *    an offset into the page file (1) or
   *    an offset into the overflow file (0)
   *  In the case of the overflow data, a VInt for length follows
   */
  protected MappedBytesInterface docFields;
 
  /** Raw overflow data */
  protected ChannelBasedMappedFile overflowFieldData;
 
  protected enum PageType {TRIE, SINGLE_VAL, MULTI_VAL};
  protected final int LEAF_MASK = 0x80000000;
  protected final int SINGLE_MASK = 0x80000000;
  private String homeDir;

  protected int getPrevLeafPage(int page) {
    // (link prev:4 + link next:4 + docs)
    return pageBi.getInt(pages.getIntOffestForPage(page));
  }

  protected int getNextLeafPage(int page) {
    // (link prev:4 + link next:4 + docs)
    return pageBi.getInt(pages.getIntOffestForPage(page)+1);
  }

  private void setPrevLeafPage(int page, int prevPage) {
    pageBi.putInt(pages.getIntOffestForPage(page), prevPage);
  }
 
  private void setNextLeafPage(int page, int nextPage) {
    pageBi.putInt(pages.getIntOffestForPage(page+1), nextPage);
  }
 
  private long descendOffset(int page, byte byteValue) {
    return pages.getIntOffestForPage(page) + 3 + (byteValue & 0xff);
  }
  private int descend(int page, byte byteValue) {
    long intOffset = descendOffset(page, byteValue);
    if (intOffset == 0) return 0;
    else return pageBi.getInt(intOffset);
  }

  private int getParentPage(int page) {
    // (link up + summary list + link complete list + 256 links down)
    return pageBi.getInt(pages.getIntOffestForPage(page));
  }
 
  private int getSummaryPage(int page) {
    // (link up + summary list + link complete list + 256 links down)
    return pageBi.getInt(pages.getIntOffestForPage(page)+1);
  }
 
  private int getLinkCompletePage(int page) {
    return pageBi.getInt(pages.getIntOffestForPage(page)+2);
  }
 
  final class LookedUpTerm {
    public int page, termPrefixLen, parentPage;
    public LookedUpTerm(int page, int termPrefixLen, int parentPage) {
      this.page = page;
      this.termPrefixLen = termPrefixLen;
      this.parentPage = parentPage;
    }
  }
 
  protected LookedUpTerm descendByTerm(byte[] term) {
    int parentPage = -1;
    int page = 0;
    int termIdx = 0;
    while(termIdx < term.length) {
      page = descend(page, term[termIdx++]);
      if ((LEAF_MASK & page) == LEAF_MASK) {
        break;
      }
    }
    return new LookedUpTerm(page, termIdx, parentPage);
  }
  protected LookedUpTerm findLeafForTerm(byte[] term) {
    LookedUpTerm result = descendByTerm(term);
    int page = result.page;
    if ((LEAF_MASK & page) != LEAF_MASK) {
      page = getLinkCompletePage(page);
    }
    result.page = page & ~LEAF_MASK;
    return result;
  }
 
  /** returns the next page */
  private int extendSingleValuedPage(int page) {
    int newPage = pages.newPageIndex();
    long offset = pages.getIntOffestForPage(page);
    pageBi.putInt(offset, newPage);
    long newPageByteOffset = pages.getByteOffestForPage(newPage);
    // 4 bytes for next page, one byte for the first vint
    for(int i=0; i<5; i++) {
      pageBi.putByte(newPageByteOffset+i, (byte) 0);
    }
    return newPage;
  }

  final class TermInDocRec implements Comparable {
    final byte[] term;
    final long docId;
    final long termValueOffset;
    final int termValueLength;
    int bump;
    public TermInDocRec(byte[] term, long docId) {
      this(term, docId, 0);
    }
    public TermInDocRec(byte[] term, long docId, long termValueOffset) {
      this.term = term;
      this.docId = docId;
      this.termValueOffset = termValueOffset;
      this.termValueLength = 0;
      this.bump = 0;
    }
    public TermInDocRec(long docId, long termValueOffset, int termValueLength) {
      this.termValueOffset = termValueOffset;
      this.termValueLength = termValueLength;
      this.docId = docId;
      this.term = null;
    }
    public TermInDocRec(long docId, TermInDocRec prev) {
      this.docId = docId;
      this.bump = prev.bump;
      this.term = prev.term;
      this.termValueOffset = prev.termValueOffset;
      this.termValueLength = prev.termValueLength;
    }
    public boolean equals(Object otherObj) {
      TermInDocRec o = (TermInDocRec)otherObj;
      if (this.term == o.term &&
        this.termValueOffset == o.termValueOffset &&
        this.termValueLength == o.termValueLength) {
        return true;
      }
      return compareTo(otherObj) == 0;
    }
    public int compareTo(Object otherObj) {
      if (bump != 0) throw new RuntimeException("Not implemented");
      TermInDocRec other = (TermInDocRec)otherObj;
      int cmp = Util.compareBytes(this.term, other.term);
      if (cmp == 0) {
        cmp = (int)(this.docId - other.docId);
      }
      return cmp;
    }
    public int getLength() {
      if (term != null) return term.length - bump;
      else return termValueLength;
    }
    public int firstByte() {
      if (term != null) {
        return term[bump];
      } else {
        throw new RuntimeException("not yet implemented");
      }
    }
    public byte[] getTerm() {
      if (term != null) {
        if (bump != 0) throw new RuntimeException("not yet implemented");
        return term;
      } else {
        throw new RuntimeException("not yet implemented");
      }
    }
    public byte getByteAt(int i) {
      if (term != null) {
        return term[bump+i];
      } else {
        return pageBi.getByte(this.termValueOffset+bump+i);
      }
    }
    public void bump(int bump) {
      if (term == null) {
        this.bump = bump;
      } else {
        throw new RuntimeException("not yet implemented");
      }
    }
  }

  class PagePlan {
    ArrayList<TermInDocRec> docs; // list of terminating docs if this is an internal node
    // one of these is null, the other is non-null:
    PagePlan[] subPlans; // always of length 256 if non-null
    public PagePlan() {
      docs = new ArrayList<TermInDocRec>();
      subPlans = null;
    }
    public PagePlan(ArrayList<TermInDocRec> docs) {
      this.docs = docs;
    }
  }
 
  private PagePlan generatePlan(List<TermInDocRec> docs) {
    // assumes input is sorted
    int numDocs = docs.size();
    PagePlan plan = new PagePlan();
    if ((numDocs <= minRecsPerPage) ||
      (docs.get(0).compareTo(docs.get(numDocs-1))==0)) {
      // no more splitting required
      for(TermInDocRec doc : docs) {
        plan.docs.add(doc);
      }
    } else {
      // split
      plan.subPlans = new PagePlan[256];
      ArrayList<TermInDocRec>[] buckets = new ArrayList[256];
      for(TermInDocRec doc : docs) {
        int len = doc.getLength();
        if (len == 0) {
          plan.docs.add(doc);
        } else {
          int insertIdx = doc.firstByte() & 0xff;
          ArrayList<TermInDocRec> bucket = buckets[insertIdx];
          if (bucket == null) {
            buckets[insertIdx] = bucket = new ArrayList<TermInDocRec>();
          }
          bucket.add(doc);
        }
      }
      int i=-1;
      for(ArrayList<TermInDocRec> bucket : buckets) {
        if (i == -1) {
          if (bucket != null) {
            plan.docs = bucket;
          }
        } else {
          if (bucket != null) {
            plan.subPlans[i-1] = generatePlan(bucket);
          }
        }
        i++;
      }
    }
    return plan;
  }
 
  private int writePlan(PagePlan plan, int parentPage) {
    int newPage = pages.newPageIndex();
    if (plan.subPlans == null) {
      // a leaf page
      TermInDocRec prev = null;
      VarPosition position = new VarPosition(pages.getByteOffestForPage(newPage  ));
      VarPosition cap      = new VarPosition(pages.getByteOffestForPage(newPage+1));
      for(TermInDocRec rec : plan.docs) {
        writeTermInDocRecAndValue(prev, rec, position, cap);
        prev = rec;
      }
    } else {
      // a trie page
      long intOffset = pages.getIntOffestForPage(newPage);
      // link up + summary list + link complete list + 256 links down
      pageBi.putInt(intOffset++, parentPage);
      pageBi.putInt(intOffset++, 0);
      if ((plan.docs != null) && (plan.docs.size() > 0)) {
        pageBi.putInt(intOffset++, writePlan(new PagePlan(plan.docs), newPage));
      } else {
        pageBi.putInt(intOffset++, 0);
      }
      pageBi.putInt(intOffset++, 0);
      for(PagePlan subPlan : plan.subPlans) {
        if (subPlan == null) {
          pageBi.putInt(intOffset++, 0);
        } else {
          int subPageId = writePlan(subPlan, newPage);
          pageBi.putInt(intOffset++, subPageId);
        }
      }
    }
    return newPage;
  }

  /** page is assumed to be a multi-valued leaf page */
  private void split(int parentPage, byte byteValue) {
    int page = descend(parentPage, byteValue);
    ArrayList<TermInDocRec> recs = parseMultiValuedLeafPage(page);
    Collections.sort(recs);
    PagePlan plan = generatePlan(recs);
    int newRootPage = writePlan(plan, parentPage);
    // swap the parent over to the new page
    pageBi.putInt(descendOffset(page, byteValue), newRootPage);
    // mark the original for deletion
    pages.markForDeletion(page);
  }

  private ArrayList<dovetaildb.bagindex.TrieBagIndex.TermInDocRec> parseMultiValuedLeafPage(int page) {
    ArrayList<TermInDocRec> recs = new ArrayList<TermInDocRec>();
    long firstPage = page;
    long nextPage = -1;
    do {
      long byteOffset = pages.getByteOffestForPage(page)+8L;
      VarPosition top = new VarPosition(pages.getByteOffestForPage(page+1));
      VarPosition vp = new VarPosition(byteOffset);
      while (true) {
        TermInDocRec rec = this.readTermInDocRec(null, vp, top);
        if (rec == null) break;
        else recs.add(rec);
      }
      nextPage = pageBi.getUInt(pages.getIntOffestForPage(page)+1);
    } while(firstPage != nextPage);
    return recs;
  }

  private int makeLeafPageUsing(List<TermInDocRec> bucket, int newTriePage) {
    int page = pages.newPageIndex();
    byte[] firstTerm = bucket.get(0).term;
    boolean isSingleValued = true;
    for(TermInDocRec rec : bucket) {
      if (Util.compareBytes(firstTerm, rec.term) != 0) {
        isSingleValued = false;
        break;
      }
    }
    long byteOffset    = pages.getByteOffestForPage(page);
    long byteOffsetCap = pages.getByteOffestForPage(page+1);
    long intOffset     = pages.getIntOffestForPage(page);
    if (isSingleValued) {
      pageBi.putInt(intOffset, SINGLE_MASK);
      VarPosition vp = new VarPosition(byteOffset + 4);
      for(TermInDocRec rec : bucket) {
        pageBi.putVLong(vp, rec.docId, byteOffsetCap);
      }
      pageBi.putVLong(vp, 0, byteOffsetCap);
    } else {
      pageBi.putByte(byteOffset++, (byte)0);
      VarPosition vp = new VarPosition(byteOffset);
      for(TermInDocRec rec : bucket) {
        pageBi.putVLong(vp, rec.docId, byteOffsetCap);
        pageBi.putVLong(vp, rec.term.length, byteOffsetCap);
        byteOffsetCap -= rec.term.length;
        pageBi.putBytes(byteOffsetCap, rec.term.length, rec.term, 0);
      }
      pageBi.putVLong(vp, 0, byteOffsetCap);
    }
    return page;
  }

  protected void backUp(VarPosition vp) {
    long i = vp.position - 2;
    while ((pageBi.getByte(i) & 0x80) == 0) {
      i--;
    }
    vp.position = i + 1;
  }
 
  protected boolean writeTermInDocRecAndValue(TermInDocRec prev, TermInDocRec rec, VarPosition position, VarPosition top) {
    int len = rec.getLength();
    if (len <= overflowThreshold) {
      if (position.position - top.position <= len) return false;
      if (! writeTermInDocRec(prev, rec, position, top.position - len)) return false;
      top.position -= len;
      pageBi.putBytes(top.position, len, rec.term, (int)rec.termValueOffset);
      return true;
    } else {
      return writeTermInDocRec(prev, rec, position, top.position);
    }
  }
 
  protected boolean writeTermInDocRec(TermInDocRec prev, TermInDocRec rec, VarPosition position, long cap) {
    if (prev.compareTo(rec) == 0) {
      return pageBi.putVLong(position, (rec.docId<<1) | 0x01, cap);
    } else {
      if (! pageBi.putVLong(position, rec.docId<<1, cap)) return false;
      int len = rec.getLength();
      if (len <= overflowThreshold) {
        if (pageBi.putVLong(position, (len<<1) | 0x01, cap)) return true;
      } else {
        // write into the overflow file
        long insertPosition = overflowFieldData.logicalAppend(rec.term, rec.bump, rec.getLength());
        if (pageBi.putVLong(position, (insertPosition<<1), cap)) {
          if (pageBi.putVLong(position, len, cap)) return true;
          else backUp(position);
        }
      }
      // success returns immediately, this is a fail:
      backUp(position);
      pageBi.putVLong(position, 0, cap);
      return false;
    }
  }

  // returns null when page is exhausted
  protected TermInDocRec readTermInDocRec(TermInDocRec prev, VarPosition position, VarPosition top) {
    long docId = pageBi.getVLong(position);
    boolean sameVal = (docId & 0x01) == 0x01;
    docId >>= 1;
    if (docId == 0) {
      return null;
    } else if (sameVal) {
      return new TermInDocRec(docId, prev);
    } else {
      int valLen = (int)pageBi.getVLong(position);
      boolean isInline = (valLen & 0x01) == 0x01;
      valLen >>= 1;
      if (isInline) {
        top.position -= valLen;
        byte[] literal = new byte[valLen];
        pageBi.getBytes(top.position, valLen, literal, 0);
        return new TermInDocRec(literal, docId);
      } else {
        long valPos = pageBi.getVLong(position);
        return new TermInDocRec(docId, valPos, valLen);
      }
    }
  }

 
  /** returns the offset to the written entry */
  protected long insertTerm(TermInDocRec rec) {
    LookedUpTerm ret   = findLeafForTerm(rec.getTerm());
    int termPrefixLen  = ret.termPrefixLen;
    int parentTriePage = ret.parentPage;
    int firstLeafPage  = ret.page;
    int lastLeafPage   = this.getPrevLeafPage(firstLeafPage); // get last page
    rec.bump(termPrefixLen);

    VarPosition pos = getDocsStartForPage(lastLeafPage);
    VarPosition top = getDocsCapForPage(lastLeafPage);
    TermInDocRec cur  = null;
    TermInDocRec prev = null;
    boolean allSame = true;
    do {
      cur = readTermInDocRec(prev, pos, top);
      if (allSame && prev != null && ! cur.equals(prev)) allSame = false;
    } while(cur!=null);
    long startingPos = pos.position;
    boolean wroteIt = writeTermInDocRecAndValue(prev, rec, pos, top);
    if (wroteIt) {
      return startingPos;
    }
    // page full, either add a new page or split the existing set
    if (allSame) {
      // add page; split may be unproductive (last page all had the same value)
      int newPage = pages.newPageIndex();
      setNextLeafPage(newPage, firstLeafPage);
      setPrevLeafPage(newPage, lastLeafPage);
      pos = getDocsStartForPage(newPage);
      top = getDocsCapForPagenewPage);
      prev=null;
      startingPos = pos.position;
      wroteIt = writeTermInDocRecAndValue(prev, rec, pos, top);
      if (! wroteIt) throw new RuntimeException();
      setNextLeafPage(lastLeafPage,  newPage);
      setPrevLeafPage(firstLeafPage, newPage);
      return startingPos;
    }
    // split the page
    byte lastByte = rec.getByteAt(termPrefixLen-1);
    split(parentTriePage, lastByte);
    // and try again
    return insertTerm(rec);
  }
 
  private VarPosition getDocsStartForPage(int leafPage) {
    long offset = pages.getByteOffestForPage(leafPage);
    // link prev:4 + link next:4 + doc list
    return new VarPosition(offset+8);
  }
  private VarPosition getDocsCapForPage(int leafPage) {
    return new VarPosition(pages.getByteOffestForPage(leafPage+1));
  }

  TrieBagIndex() {
    this(1036, 8);
  }
  TrieBagIndex(int pageSize, int overflowThreshold) {
    this.pageSize = 0;
    this.overflowThreshold = overflowThreshold;
    this.minRecsPerPage = (pageSize - 8)/(overflowThreshold+20);
  }

  @Override
  public void close() {
    pages.close();
  }

  @Override
  public long commitNewRev(long[] deletions,
      Collection<Pair<byte[][], byte[][]>> inserts) {
    int numInserts = inserts.size();
    long revNum = maxDocId + numInserts;
    if (numInserts == 0) {
      // commits with only deletions occupy a docId space, so pre-delete it
      inserts.add(new Pair<byte[][],byte[][]>(null,null));
      revNum++;
    }
   
    Arrays.sort(deletions);
    deleteInRev(deletions, revNum);

    ByteArrayOutputStream docEntryBuf = new ByteArrayOutputStream();
    ByteArrayOutputStream termValueBuf = new ByteArrayOutputStream();
    VIntScanner.writeVLong(docEntryBuf, (long)termValueBuf.size());
    byte[][][] groups = new byte[2][][];
    for(Pair<byte[][],byte[][]> docPair : inserts) {

      byte[][] indexTerms = docPair.getLeft();
      byte[][] storeTerms = docPair.getRight();
      groups[0] = storeTerms;
      groups[1] = indexTerms;
      for(byte[][] insertTerms : groups) {
        for(byte[] term : insertTerms) {
          long sz = term.length;
          VIntScanner.writeVLong(docEntryBuf, sz);
          try { termValueBuf.write(term); }
          catch (IOException e) { throw new RuntimeException(e); }
          //if (insertTerms == indexTerms) {
          TermInDocRec rec = new TermInDocRec(term, maxDocId);
          long dataPosition = insertTerm(rec);
          //}
        }
      }
      maxDocId++;
    }
    pageBi.force();
    maxDocIdFile.putLong(0, maxDocId);
    maxDocIdFile.force();
    return maxDocId;
  }

  protected void deleteInRev(long[] deletions, long revNum) {
    byte[] delTerm = new byte[2+8];
    delTerm[0] = 0;
    delTerm[1] = 'd';
    TermInDocRec rec = new TermInDocRec(delTerm, revNum, 2+8);
    for(long deletion : deletions) {
      Util.beLongToBytes(deletion, delTerm, 2);
      this.insertTerm(rec);
    }
  }

 

  public void fetchSubRange(
      int rootPage, int termIdx,
      ArrayList<Scanner> scanners,
      byte[] term1, byte[] term2,
      boolean isOpen1, boolean isOpen2, 
      boolean isExclusive1, boolean isExclusive2,
      long revNum, Score score) {
    long offset = this.getTrieStartForPage(rootPage);
    long t1 = isOpen1 || termIdx>=term1.length ? 0   : term1[termIdx] & 0xff;
    long t2 = isOpen2 || termIdx>=term2.length ? 255 : term2[termIdx] & 0xff;
    for(long t = t1; t <= t2; t++) {
      int page = pageBi.getInt(offset + t);
      if (page == 0) { // dead end
        continue;
      }
      boolean isLeaf = (LEAF_MASK & page) == LEAF_MASK;
      if (isLeaf) {
        page &= ~LEAF_MASK;
        scanners.add(new LeafScanner(page, revNum, score));
      } else {
        Score nextScore = null;
        if (score != null) {
          nextScore = score.duplicate();
          nextScore.add((byte)t);
        }
        fetchSubRange(page, termIdx+1, scanners, term1, term2,
            t>t1 || isOpen1, t<t2 || isOpen2,
            isExclusive1, isExclusive2, revNum, nextScore);
      }
    }
  }

  private long getTrieStartForPage(int page) {
    //    Trie page (link up + summary list + link complete list + 256 links down)
    return pages.getIntOffestForPage(page) + 3;
  }

  @Override
  public Scanner fetchRange(byte[] prefix,
      byte[] term1, byte[] term2,
      boolean isExclusive1, boolean isExclusive2,
      long revNum, Scorer scorer) {
    Score score = scorer == null ? null : scorer.newScore();
    LookedUpTerm prefixResult = descendByTerm(prefix);
    for(int i=0; i < prefixResult.termPrefixLen; i++) {
      score.add(prefix[i]);
    }
    final int page = prefixResult.page;
    boolean isLeaf = (LEAF_MASK & page) == LEAF_MASK;
    if (isLeaf) {
      return new LeafScanner(page, revNum, score);
    } else {
      ArrayList<Scanner> scanners = new ArrayList<Scanner>();
      fetchSubRange(page, 0, scanners, term1, term2, false, false,
          isExclusive1, isExclusive2, revNum, score);
      return ScannerUtil.conjunctiveScanner(scanners);
    }
  }

  private final class LeafScanner extends AbstractScanner {
    int page, firstPage;
    VarPosition pos, top;
    TermInDocRec cur  = null;
    TermInDocRec prev = null;
    long revNum;
    double min, max;

    LeafScanner(int firstPage, long revNum, Score score) {
      this.firstPage = firstPage;
      int page = firstPage;
      pos = getDocsStartForPage(page);
      top = getDocsCapForPage(page);
      this.revNum = revNum;
      if (score == null) {
        this.min = Double.MIN_VALUE;
        this.max = Double.MAX_VALUE;
      } else {
        this.min = score.min();
        this.max = score.max();
      }
    }
    public long doc() {
      return cur.docId;
    }
    public boolean next() {
      cur = readTermInDocRec(prev, pos, top);
      while (cur == null) { // try next page
        page = getNextLeafPage(page);
        if (page == firstPage) {
          return false;
        } else {
          pos = getDocsStartForPage(page);
          top = getDocsCapForPage(page);
          cur = readTermInDocRec(prev, pos, top);
          prev = null;
        }
      }
      return true;
    }
   
    public boolean dropDocsScoringLessThan(double amount) {
      if (amount > max) {
        cur = null;
        return false;
      } else {
        return true;
      }
    }

    public boolean dropDocsScoringMoreThan(double amount) {
      if (amount < min) {
        cur = null;
        return false;
      } else {
        return true;
      }
    }

  }
 
  @Override
  public Scanner fetchTd(byte[] term, long revNum) {
    LookedUpTerm leaf = findLeafForTerm(term);
    int firstPage = leaf.page;
    return new LeafScanner(firstPage, revNum, null);
  }

  @Override
  public Scanner fetchAll(long revNum) {
    return new IntegerScanner(revNum);
  }

  @Override
  public Scanner fetchDeletions(long revNum) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public BagIndexDoc fetchDoc(long docId) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public BagIndexDoc refetchDoc(BagIndexDoc doc, long docId) {
    return fetchDoc(docId);
  }

  @Override
  public String getHomedir() {
    // TODO Auto-generated method stub
    return null;
  }

  protected FileChannel openFile(String name) {
    String filename = homeDir + File.separatorChar + "maxdocid";
    RandomAccessFile maxDocIdRaf;
    try {
      maxDocIdRaf = new RandomAccessFile(new File(filename), "rw");
      return maxDocIdRaf.getChannel();
    } catch (FileNotFoundException e) {
      throw new RuntimeException(e);
    }
  }
 
  @Override
  public void setHomedir(String homeDir) {
    try {
      this.homeDir = homeDir;
     
      File pagesFile = new File(homeDir+File.separatorChar+"pages");
      boolean newIndex = ! pagesFile.exists();
      if (newIndex) {
        System.out.println("No index present at "+homeDir+"; creating a new index.");
      }

      pages = new PagedFile(pagesFile);
      pageBi = pages.getBytesInterface();
     
      maxDocIdFile      = new MappedBytesInterface(openFile("maxdocid"));
      if (newIndex) {
        maxDocIdFile = maxDocIdFile.ensureSizeAtLeast(8);
        maxDocIdFile.putLong(0, 0);
       
        int pageLocation = writePlan(new PagePlan(), 0);
        if (pageLocation != 0)
          throw new RuntimeException("page location not at root - unexpected");

      }
      docIdToDoc        = new MappedBytesInterface(openFile("docidtodoc"));
      docFields         = new MappedBytesInterface(openFile("docfields"));
      overflowFieldData = new ChunkedMemoryMappedFile(openFile("overflow"));
     
      this.maxDocId = maxDocIdFile.getLong(0);
     
    } catch (FileNotFoundException e) {
      throw new RuntimeException(e);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  @Override
  public long getCurrentRevNum() {
    return maxDocId;
  }

}
TOP

Related Classes of dovetaildb.bagindex.TrieBagIndex

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.