Package org.openrdf.sail.rdbms.managers

Source Code of org.openrdf.sail.rdbms.managers.TripleTableManager

/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 2008.
*
* Licensed under the Aduna BSD-style license.
*/
package org.openrdf.sail.rdbms.managers;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.openrdf.sail.rdbms.schema.IdSequence;
import org.openrdf.sail.rdbms.schema.TripleTable;
import org.openrdf.sail.rdbms.schema.ValueTableFactory;

/**
* Manages and delegates to the collection of {@link TripleTable}.
*
* @author James Leigh
*/
public class TripleTableManager {

  private static final String DEFAULT_TABLE_PREFIX = "TRIPLES";

  private static final String OTHER_TRIPLES_TABLE = "TRIPLES";

  private static final boolean USE_THREAD = true;

  public static int MAX_TABLES = Integer.MAX_VALUE;// 1000;

  public static final boolean INDEX_TRIPLES = true;

  public Number OTHER_PRED;

  private BNodeManager bnodes;

  private volatile boolean closed;

  private Connection conn;

  private ValueTableFactory factory;

  private Thread initThread;

  private LiteralManager literals;

  Logger logger = LoggerFactory.getLogger(TripleTableManager.class);

  private PredicateManager predicates;

  private LinkedList<TripleTable> queue = new LinkedList<TripleTable>();

  private Pattern tablePrefix = Pattern.compile("\\W(\\w*)\\W*$");

  private Map<Number, TripleTable> tables = new HashMap<Number, TripleTable>();

  private UriManager uris;

  private HashManager hashes;

  private int maxTables = MAX_TABLES;

  private volatile boolean indexingTriples = INDEX_TRIPLES;

  private IdSequence ids;

  volatile Exception exc;

  public TripleTableManager(ValueTableFactory factory) {
    this.factory = factory;
  }

  public void setConnection(Connection conn) {
    this.conn = conn;
  }

  public void setIdSequence(IdSequence ids) {
    this.ids = ids;
    this.OTHER_PRED = ids.idOf(Long.valueOf(-1));
  }

  public void setPredicateManager(PredicateManager predicates) {
    this.predicates = predicates;
  }

  public void setBNodeManager(BNodeManager bnodeTable) {
    this.bnodes = bnodeTable;
  }

  public void setLiteralManager(LiteralManager literalTable) {
    this.literals = literalTable;
  }

  public void setUriManager(UriManager uriTable) {
    this.uris = uriTable;
  }

  public void setHashManager(HashManager hashes) {
    this.hashes = hashes;
  }

  public int getMaxNumberOfTripleTables() {
    if (maxTables == Integer.MAX_VALUE) {
      return 0;
    }
    return maxTables + 1;
  }

  public void setMaxNumberOfTripleTables(int max) {
    if (max < 1) {
      maxTables = MAX_TABLES;
    }
    else {
      maxTables = max - 1;
    }
  }

  public boolean isIndexingTriples() {
    return indexingTriples;
  }

  public void setIndexingTriples(boolean indexingTriples) {
    this.indexingTriples = indexingTriples;
  }

  public void initialize()
    throws SQLException
  {
    tables.putAll(findPredicateTables());
    if (USE_THREAD) {
      initThread = new Thread(new Runnable() {

        public void run() {
          try {
            initThread();
          }
          catch (Exception e) {
            exc = e;
            logger.error(e.toString(), e);
          }
        }
      }, "table-initialize");
      initThread.start();
    }
  }

  public void close()
    throws SQLException
  {
    closed = true;
    synchronized (queue) {
      queue.notify();
    }
    Iterator<Entry<Number, TripleTable>> iter;
    iter = tables.entrySet().iterator();
    while (iter.hasNext()) {
      Entry<Number, TripleTable> next = iter.next();
      TripleTable table = next.getValue();
      if (table.isEmpty()) {
        predicates.remove(next.getKey());
        table.drop();
        iter.remove();
      }
      table.close();
    }
  }

  public void createTripleIndexes()
    throws SQLException
  {
    indexingTriples = true;
    for (TripleTable table : tables.values()) {
      if (!table.isIndexed()) {
        table.createIndex();
      }
    }
  }

  public void dropTripleIndexes()
    throws SQLException
  {
    indexingTriples = false;
    for (TripleTable table : tables.values()) {
      if (table.isIndexed()) {
        table.dropIndex();
      }
    }
  }

  public String findTableName(Number pred)
    throws SQLException
  {
    return getPredicateTable(pred).getNameWhenReady();
  }

  public synchronized TripleTable getExistingTable(Number pred) {
    if (tables.containsKey(pred)) {
      return tables.get(pred);
    }
    return tables.get(OTHER_PRED);
  }

  public synchronized Collection<Number> getPredicateIds() {
    return new ArrayList<Number>(tables.keySet());
  }

  public synchronized TripleTable getPredicateTable(Number pred)
    throws SQLException
  {
    assert pred.longValue() != 0;
    assert pred.equals(ids.idOf(pred));
    if (tables.containsKey(pred)) {
      return tables.get(pred);
    }
    if (tables.containsKey(OTHER_PRED)) {
      return tables.get(OTHER_PRED);
    }
    String tableName = getNewTableName(pred);
    if (tables.size() >= maxTables) {
      tableName = OTHER_TRIPLES_TABLE;
    }
    TripleTable table = factory.createTripleTable(conn, tableName);
    table.setIdSequence(ids);
    if (tables.size() >= maxTables) {
      table.setPredColumnPresent(true);
      initTable(table);
      tables.put(OTHER_PRED, table);
    }
    else {
      initTable(table);
      tables.put(pred, table);
    }
    return table;
  }

  public synchronized String getTableName(Number pred)
    throws SQLException
  {
    if (tables.containsKey(pred)) {
      return tables.get(pred).getNameWhenReady();
    }
    if (tables.containsKey(OTHER_PRED)) {
      return tables.get(OTHER_PRED).getNameWhenReady();
    }
    return null;
  }

  public void removed(int count, boolean locked)
    throws SQLException
  {
    String condition = null;
    if (locked) {
      condition = getExpungeCondition();
    }
    if (hashes != null) {
      if (hashes.removedStatements(count, condition)) {
        condition = hashes.getExpungeCondition();
      }
      else {
        condition = null;
      }
    }
    if (condition != null) {
      bnodes.removedStatements(condition);
      uris.removedStatements(condition);
      literals.removedStatements(condition);
    }
  }

  protected Set<String> findAllTables()
    throws SQLException
  {
    Set<String> tables = new HashSet<String>();
    DatabaseMetaData metaData = conn.getMetaData();
    String c = null;
    String s = null;
    String n = null;
    String[] TYPE_TABLE = new String[] { "TABLE" };
    ResultSet rs = metaData.getTables(c, s, n, TYPE_TABLE);
    try {
      while (rs.next()) {
        String tableName = rs.getString(3);
        tables.add(tableName);
      }
      return tables;
    }
    finally {
      rs.close();
    }
  }

  protected Map<Number, TripleTable> findPredicateTables()
    throws SQLException
  {
    Map<Number, TripleTable> tables = new HashMap<Number, TripleTable>();
    Set<String> names = findPredicateTableNames();
    for (String tableName : names) {
      TripleTable table = factory.createTripleTable(conn, tableName);
      table.setIdSequence(ids);
      if (tableName.equalsIgnoreCase(OTHER_TRIPLES_TABLE)) {
        table.setPredColumnPresent(true);
      }
      if (indexingTriples && !table.isIndexed()) {
        table.createIndex();
      }
      table.reload();
      tables.put(key(tableName), table);
    }
    return tables;
  }

  protected Set<String> findTablesWithColumn(String column)
    throws SQLException
  {
    Set<String> tables = findTablesWithExactColumn(column.toUpperCase());
    if (tables.isEmpty()) {
      return findTablesWithExactColumn(column.toLowerCase());
    }
    return tables;
  }

  protected Set<String> findTablesWithExactColumn(String column)
    throws SQLException
  {
    Set<String> tables = new HashSet<String>();
    DatabaseMetaData metaData = conn.getMetaData();
    String c = null;
    String s = null;
    String n = null;
    ResultSet rs = metaData.getColumns(c, s, n, column);
    try {
      while (rs.next()) {
        String tableName = rs.getString(3);
        tables.add(tableName);
      }
      return tables;
    }
    finally {
      rs.close();
    }
  }

  protected synchronized String getExpungeCondition()
    throws SQLException
  {
    StringBuilder sb = new StringBuilder(1024);
    for (Map.Entry<Number, TripleTable> e : tables.entrySet()) {
      sb.append("\nAND id <> ").append(e.getKey());
      if (e.getValue().isEmpty()) {
        continue;
      }
      sb.append(" AND NOT EXISTS (SELECT * FROM ");
      sb.append(e.getValue().getNameWhenReady());
      sb.append(" WHERE ctx = id OR subj = id OR obj = id");
      if (e.getValue().isPredColumnPresent()) {
        sb.append(" OR pred = id");
      }
      sb.append(")");
    }
    return sb.toString();
  }

  protected String getNewTableName(Number pred)
    throws SQLException
  {
    String prefix = getTableNamePrefix(pred);
    String tableName = prefix + "_" + pred;
    return tableName;
  }

  protected Number key(String tn) {
    if (tn.equalsIgnoreCase(OTHER_TRIPLES_TABLE)) {
      return OTHER_PRED;
    }
    Number id = ids.idOf(Long.valueOf(tn.substring(tn.lastIndexOf('_') + 1)));
    assert id.longValue() != 0;
    return id;
  }

  protected String getTableNamePrefix(Number pred)
    throws SQLException
  {
    String uri = predicates.getPredicateUri(pred);
    if (uri == null) {
      return DEFAULT_TABLE_PREFIX;
    }
    Matcher m = tablePrefix.matcher(uri);
    if (!m.find()) {
      return DEFAULT_TABLE_PREFIX;
    }
    String localName = m.group(1).replaceAll("^[^a-zA-Z]*", "");
    if (localName.length() == 0) {
      return DEFAULT_TABLE_PREFIX;
    }
    if (localName.length() > 16) {
      return localName.substring(0, 16);
    }
    return localName;
  }

  void initThread()
    throws SQLException, InterruptedException
  {
    logger.debug("Starting helper thread {}", initThread.getName());
    while (!closed) {
      TripleTable table = null;
      synchronized (queue) {
        if (queue.isEmpty()) {
          queue.wait();
        }
        if (!queue.isEmpty()) {
          table = queue.removeFirst();
        }
      }
      if (table != null) {
        table.initTable();
        table = null;
      }
    }
    logger.debug("Closing helper thread {}", initThread.getName());
  }

  private Set<String> findPredicateTableNames()
    throws SQLException
  {
    Set<String> names = findAllTables();
    names.retainAll(findTablesWithColumn("ctx"));
    names.retainAll(findTablesWithColumn("subj"));
    names.retainAll(findTablesWithColumn("obj"));
    return names;
  }

  private void initTable(TripleTable table)
    throws SQLException
  {
    if (exc != null) {
      throwException();
    }
    table.setIndexed(indexingTriples);
    if (true || queue == null) {
      table.initTable();
    }
    else {
      synchronized (queue) {
        queue.add(table);
        queue.notify();
      }
    }
  }

  private void throwException()
    throws SQLException
  {
    if (exc instanceof SQLException) {
      SQLException e = (SQLException)exc;
      exc = null;
      throw e;
    }
    else if (exc instanceof RuntimeException) {
      RuntimeException e = (RuntimeException)exc;
      exc = null;
      throw e;
    }
  }
}
TOP

Related Classes of org.openrdf.sail.rdbms.managers.TripleTableManager

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.