Package org.teiid.common.buffer

Source Code of org.teiid.common.buffer.TupleBrowser

/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.  Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/

package org.teiid.common.buffer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.teiid.common.buffer.SPage.SearchResult;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;

/**
* Implements intelligent browsing over a {@link STree}
*
* TODO: this is not as efficient as it should be over partial matches
*/
public class TupleBrowser implements TupleSource {
 
  private final STree tree;
 
  private TupleSource valueSet;
 
  private SPage page;
  private int index;
 
  private SPage bound;
  private int boundIndex = -1;
 
  private TupleBatch values;
  private boolean updated;
  private boolean direction;
 
  private boolean inPartial;

  /**
   * Construct a value based browser.  The {@link TupleSource} should already be in the
   * proper direction.
   * @param sTree
   * @param valueSet
   * @param direction
   */
  public TupleBrowser(STree sTree, TupleSource valueSet, boolean direction) {
    this.tree = sTree;
    this.direction = direction;
    this.valueSet = valueSet;
  }
 
  /**
   * Construct a range based browser
   * @param sTree
   * @param lowerBound
   * @param upperBound
   * @param direction
   * @throws TeiidComponentException
   */
  public TupleBrowser(STree sTree, List<Object> lowerBound, List<Object> upperBound, boolean direction) throws TeiidComponentException {
    this.tree = sTree;
    this.direction = direction;
   
    init(lowerBound, upperBound, false);
  }

  private void init(List<Object> lowerBound,
      List<?> upperBound, boolean isPartialKey)
      throws TeiidComponentException {
    if (lowerBound != null) {
      lowerBound.addAll(Collections.nCopies(tree.getKeyLength() - lowerBound.size(), null));
      setPage(lowerBound);
    } else {
      page = tree.header[0];
    }
   
    boolean valid = true;
   
    if (upperBound != null) {
      if (!isPartialKey && lowerBound != null && this.tree.comparator.compare(upperBound, lowerBound) < 0) {
        valid = false;
      }
      LinkedList<SearchResult> places = new LinkedList<SearchResult>();
      this.tree.find(upperBound, places);
      SearchResult upper = places.getLast();
      bound = upper.page;
      boundIndex = upper.index;
      if (boundIndex < 0) {
        //we are guaranteed by find to not get back the -1 index, unless
        //there are no tuples, in which case a bound of -1 is fine
        boundIndex = Math.min(upper.values.getTuples().size(), -boundIndex -1) - 1;
      }
      if (!direction) {
        values = upper.values;
      }
      if (lowerBound != null) {
        valid = index<=boundIndex;
      }
    } else {
      while (bound == null || bound.children != null) {
        bound = tree.findChildTail(bound);
      }
      if (!direction) {
        if (page != bound || values == null) {
          values = bound.getValues();
        }
        boundIndex = values.getTuples().size() - 1;
      }
    }
       
    if (!direction) {
      SPage swap = page;
      page = bound;
      bound = swap;
      int upperIndex = boundIndex;
      boundIndex = index;
      index = upperIndex;
    }
   
    if (!valid) {
      page = null;
    }
  }

  private boolean setPage(List<?> lowerBound) throws TeiidComponentException {
    LinkedList<SearchResult> places = new LinkedList<SearchResult>();
    this.tree.find(lowerBound, places);
   
    SearchResult sr = places.getLast();
    page = sr.page;
    index = sr.index;
    boolean result = true;
    if (index < 0) {
      result = false;
      index = -index - 1;
    }
    values = sr.values;
    return result;
  }
 
  @Override
  public List<?> nextTuple() throws TeiidComponentException,
      TeiidProcessingException {
    for (;;) {
      //first check for value iteration
      if (!inPartial && valueSet != null) {
        List<?> newValue = valueSet.nextTuple();
        if (newValue == null) {
          resetState();
          return null;
        }
        if (newValue.size() < tree.getKeyLength()) {
          init(new ArrayList<Object>(newValue), newValue, true);
          inPartial = true;
          continue;
        }
        if (values != null) {
          int possibleIndex = Collections.binarySearch(values.getTuples(), newValue, tree.comparator);
          if (possibleIndex >= 0) {
            //value exists in the current page
            index = possibleIndex;
            return values.getTuples().get(possibleIndex);
          }
          //check for end/terminal conditions
          if (direction && possibleIndex == -values.getTuples().size() -1) {
            if (page.next == null) {
              resetState();
              return null;
            }
          } else if (!direction && possibleIndex == -1) {
            if (page.prev == null) {
              resetState();
              return null;
            }
          } else {
            //the value simply doesn't exist
            continue;
          }
        }
        resetState();
        if (!setPage(newValue)) {
          continue;
        }
        return values.getTuples().get(index);
      }
      if (page == null) {
        if (inPartial) {
          inPartial = false;
          continue;
        }
        return null;
      }
      if (values == null) {
        values = page.getValues();
        if (direction) {
          index = 0;
        } else {
          index = values.getTuples().size() - 1;
        }
      }
      if (index >= 0 && index < values.getTuples().size()) {
        List<?> result = values.getTuples().get(index);
        if (page == bound && index == boundIndex) {
          resetState();
          page = null; //terminate
        } else {
          index+=getOffset();
        }
        return result;
      }
      resetState();
      if (direction) {
        page = page.next;
      } else {
        page = page.prev;
      }
    }
  }

  private void resetState() throws TeiidComponentException {
    if (updated) {
      page.setValues(values);
    }
    updated = false;
    values = null;
  }
 
  private int getOffset() {
    if (!inPartial && valueSet != null) {
      return 0;
    }
    return direction?1:-1;
  }
 
  /**
   * Perform an in-place update of the tuple just returned by the next method
   * WARNING - this must not change the key value
   * @param tuple
   * @throws TeiidComponentException
   */
  public void update(List<?> tuple) throws TeiidComponentException {
    values.getTuples().set(index - getOffset(), tuple);
    updated = true;
  }
 
  /**
   * Notify the browser that the last value was deleted.
   */
  public void removed() {
    index-=getOffset();
  }
 
  @Override
  public void closeSource() {
   
  }
 
}
TOP

Related Classes of org.teiid.common.buffer.TupleBrowser

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.