/* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * !# */ package net.ontopia.topicmaps.query.impl.utils; import java.util.Arrays; import java.util.Collection; import net.ontopia.infoset.fulltext.core.DocumentIF; import net.ontopia.infoset.fulltext.core.FieldIF; import net.ontopia.infoset.fulltext.core.SearchResultIF; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.core.TopicMapIF; import net.ontopia.topicmaps.core.TopicMapStoreIF; import net.ontopia.topicmaps.impl.rdbms.RDBMSTopicMapStore; import net.ontopia.topicmaps.query.impl.basic.QueryMatches; import net.ontopia.utils.CompactHashSet; import net.ontopia.utils.PropertyUtils; import net.ontopia.utils.OntopiaRuntimeException; /** * INTERNAL: Prefetching utility */ public class Prefetcher { // class type constants public static final int AssociationIF = 0; public static final int AssociationRoleIF = 1; public static final int TopicNameIF = 2; public static final int OccurrenceIF = 3; public static final int TopicIF = 4; public static final int TopicMapIF = 5; public static final int VariantNameIF = 6; // AssociationIF public static final int AssociationIF_sources = 0; public static final int AssociationIF_topicmap = 1; public static final int AssociationIF_scope = 2; public static final int AssociationIF_type = 3; public static final int AssociationIF_roles = 4; // AssociationRoleIF public static final int AssociationRoleIF_sources = 0; public static final int AssociationRoleIF_topicmap = 1; public static final int AssociationRoleIF_association = 2; public static final int AssociationRoleIF_type = 3; public static final int AssociationRoleIF_player = 4; // TopicNameIF public static final int TopicNameIF_sources = 0; public static final int TopicNameIF_topicmap = 1; public static final int TopicNameIF_topic = 2; public static final int TopicNameIF_scope = 3; public static final int TopicNameIF_type = 4; public static final int TopicNameIF_value = 5; public static final int TopicNameIF_variants = 6; // OccurrenceIF public static final int OccurrenceIF_sources = 0; public static final int OccurrenceIF_topicmap = 1; public static final int OccurrenceIF_topic = 2; public static final int OccurrenceIF_scope = 3; public static final int OccurrenceIF_type = 4; public static final int OccurrenceIF_value = 5; public static final int OccurrenceIF_locator = 6; // TopicIF public static final int TopicIF_sources = 0; public static final int TopicIF_topicmap = 1; public static final int TopicIF_subject = 2; public static final int TopicIF_indicators = 3; public static final int TopicIF_scope = 4; public static final int TopicIF_types = 5; public static final int TopicIF_names = 6; public static final int TopicIF_occurrences = 7; public static final int TopicIF_roles = 8; // TopicMapIF public static final int TopicMapIF_sources = 0; public static final int TopicMapIF_scope = 1; // VariantNameIF public static final int VariantNameIF_sources = 0; public static final int VariantNameIF_topicmap = 1; public static final int VariantNameIF_name = 2; public static final int VariantNameIF_scope = 3; public static final int VariantNameIF_value = 4; public static final int VariantNameIF_locator = 5; // ----------------------------------------------------------------------------- // Object[] prefetching // ----------------------------------------------------------------------------- public static boolean prefetch(TopicMapIF tm, Object[] objects, int type, int field, boolean traverse) { if (!doPrefetch(tm)) return false; // no prefetching if no hits if (objects == null || objects.length == 0) return false; // prefetch fields in rdbms implementation return ((net.ontopia.topicmaps.impl.rdbms.RDBMSTopicMapStore)tm.getStore()) .prefetch(type, field, traverse, Arrays.asList(objects)); } public static boolean prefetch(TopicMapIF tm, Object[] objects, int type, int[] fields, boolean[] traverse) { if (!doPrefetch(tm)) return false; // no prefetching if no hits if (objects == null || objects.length == 0) return false; // prefetch fields in rdbms implementation return ((net.ontopia.topicmaps.impl.rdbms.RDBMSTopicMapStore)tm.getStore()) .prefetch(type, fields, traverse, Arrays.asList(objects)); } // ----------------------------------------------------------------------------- // Collection prefetching // ----------------------------------------------------------------------------- public static boolean prefetch(TopicMapIF tm, Collection objects, int type, int field, boolean traverse) { if (!doPrefetch(tm)) return false; // no prefetching if no hits if (objects.isEmpty()) return false; // prefetch fields in rdbms implementation return ((net.ontopia.topicmaps.impl.rdbms.RDBMSTopicMapStore)tm.getStore()) .prefetch(type, field, traverse, objects); } public static boolean prefetch(TopicMapIF tm, Collection objects, int type, int[] fields, boolean[] traverse) { if (!doPrefetch(tm)) return false; // no prefetching if no hits if (objects.isEmpty()) return false; // prefetch fields in rdbms implementation return ((net.ontopia.topicmaps.impl.rdbms.RDBMSTopicMapStore)tm.getStore()) .prefetch(type, fields, traverse, objects); } // ----------------------------------------------------------------------------- // QueryMatches prefetching // ----------------------------------------------------------------------------- public static boolean prefetch(TopicMapIF tm, QueryMatches matches, int qmidx, int type, int field, boolean traverse) { if (!doPrefetch(tm)) return false; // no prefetching if no hits if (matches.last < 0) return false; // prefetch fields in rdbms implementation return ((net.ontopia.topicmaps.impl.rdbms.RDBMSTopicMapStore)tm.getStore()) .prefetch(type, field, traverse, new QueryMatchesCollection(matches, qmidx)); } public static boolean prefetch(TopicMapIF tm, QueryMatches matches, int qmidx, int type, int[] fields, boolean[] traverse) { if (!doPrefetch(tm)) return false; // no prefetching if no hits if (matches.last < 0) return false; // prefetch fields in rdbms implementation return ((net.ontopia.topicmaps.impl.rdbms.RDBMSTopicMapStore)tm.getStore()) .prefetch(type, fields, traverse, new QueryMatchesCollection(matches, qmidx)); } // ----------------------------------------------------------------------------- // SearchResultIF prefetch // ----------------------------------------------------------------------------- public static boolean prefetch(TopicMapIF tm, SearchResultIF result, String idfname) { if (!doPrefetch(tm)) return false; // no prefetching if no hits try { int size = result.hits(); if (size <= 1) return false; // extract object ids Collection oids = new CompactHashSet(size); for (int i=0; i < size; i++) { DocumentIF doc = result.getDocument(i); FieldIF idfield = doc.getField(idfname); if (idfield == null) continue; String idval = idfield.getValue(); if (idval == null) continue; oids.add(idval); } // prefetch objects in rdbms implementation return ((net.ontopia.topicmaps.impl.rdbms.RDBMSTopicMapStore)tm.getStore()) .prefetchObjectsById(oids); } catch (java.io.IOException e) { throw new OntopiaRuntimeException(e); } } // ----------------------------------------------------------------------------- // Specialized prefetch hacks // ----------------------------------------------------------------------------- public static boolean prefetchRolesByType(TopicMapIF tm, QueryMatches matches, int qmidx, TopicIF rtype, int[] fields, boolean[] traverse) { if (!doPrefetch(tm)) return false; // no prefetching if no hits if (matches.last < 0) return false; // NOTE: taking advantage of the fact that the // TopicIF.getRolesByType results are being cached // collect roles by type Collection roles = new CompactHashSet(); for (int row = 0; row <= matches.last; row++) { TopicIF topic = (TopicIF) matches.data[row][qmidx]; roles.addAll(topic.getRolesByType(rtype)); } // prefetch starting with roles return Prefetcher.prefetch(tm, roles, Prefetcher.AssociationRoleIF, fields, traverse); } public static boolean prefetchRolesByType(TopicMapIF tm, QueryMatches matches, int qmidx, TopicIF rtype, TopicIF atype, int[] fields, boolean[] traverse) { if (!doPrefetch(tm)) return false; // no prefetching if no hits if (matches.last < 0) return false; Collection players = new QueryMatchesCollection(matches, qmidx); ((net.ontopia.topicmaps.impl.rdbms.RDBMSTopicMapStore)tm.getStore()) .prefetchRolesByType(players, rtype, atype); return true; } // ----------------------------------------------------------------------------- // Internal helper methods // ----------------------------------------------------------------------------- private static boolean doPrefetch(TopicMapIF tm) { if (tm.getStore().getImplementation() != TopicMapStoreIF.RDBMS_IMPLEMENTATION) return false; RDBMSTopicMapStore store = (RDBMSTopicMapStore) tm.getStore(); // no prefetching if shared cache is disabled if (!PropertyUtils.isTrue(store.getProperty("net.ontopia.topicmaps.impl.rdbms.Cache.shared"), true)) return false; // default is true, but check prefetch property String value = store.getProperty("net.ontopia.topicmaps.query.core.prefetch"); if (value == null) return true; // on by default value = value.trim().toLowerCase(); return value.equals("true"); } }