private static Collection<OIndex<?>> prepareLastIndexVariants( OClass iSchemaClass, OSQLFilterItemField.FieldChain fieldChain) { OClass oClass = iSchemaClass; final Collection<OIndex<?>> result = new ArrayList<OIndex<?>>(); for (int i = 0; i < fieldChain.getItemCount() - 1; i++) { oClass = oClass.getProperty(fieldChain.getItemName(i)).getLinkedClass(); if (oClass == null) { return result; } } final Set<OIndex<?>> involvedIndexes = new TreeSet<OIndex<?>>( new Comparator<OIndex<?>>() { public int compare(OIndex<?> o1, OIndex<?> o2) { return o1.getDefinition().getParamCount() - o2.getDefinition().getParamCount(); } }); involvedIndexes.addAll( oClass.getInvolvedIndexes(fieldChain.getItemName(fieldChain.getItemCount() - 1))); final Collection<Class<? extends OIndex>> indexTypes = new HashSet<Class<? extends OIndex>>(3); for (OIndex<?> involvedIndex : involvedIndexes) { if (!indexTypes.contains(involvedIndex.getInternal().getClass())) { result.add(involvedIndex); indexTypes.add(involvedIndex.getInternal().getClass()); } } return result; }
@Override public Object executeIndexQuery( OCommandContext iContext, OIndex<?> index, final INDEX_OPERATION_TYPE iOperationType, List<Object> keyParams, int fetchLimit) { final OIndexDefinition indexDefinition = index.getDefinition(); final OIndexInternal<?> internalIndex = index.getInternal(); if (!internalIndex.canBeUsedInEqualityOperators()) return null; final Object result; if (indexDefinition.getParamCount() == 1) { final Object key; if (indexDefinition instanceof OIndexDefinitionMultiValue) key = ((OIndexDefinitionMultiValue) indexDefinition).createSingleValue(keyParams.get(0)); else key = indexDefinition.createValue(keyParams); if (key == null) return null; final Object indexResult; if (iOperationType == INDEX_OPERATION_TYPE.GET) indexResult = index.get(key); else indexResult = index.count(key); result = convertIndexResult(indexResult); } else { // in case of composite keys several items can be returned in case of we perform search // using part of composite key stored in index. final OCompositeIndexDefinition compositeIndexDefinition = (OCompositeIndexDefinition) indexDefinition; final Object keyOne = compositeIndexDefinition.createSingleValue(keyParams); if (keyOne == null) return null; final Object keyTwo = compositeIndexDefinition.createSingleValue(keyParams); if (internalIndex.hasRangeQuerySupport()) { if (INDEX_OPERATION_TYPE.COUNT.equals(iOperationType)) { result = index.count(keyOne, true, keyTwo, true, fetchLimit); } else if (fetchLimit > -1) result = index.getValuesBetween(keyOne, true, keyTwo, true, fetchLimit); else result = index.getValuesBetween(keyOne, true, keyTwo, true); } else { if (indexDefinition.getParamCount() == keyParams.size()) { final Object indexResult; if (iOperationType == INDEX_OPERATION_TYPE.GET) indexResult = index.get(keyOne); else indexResult = index.count(keyOne); result = convertIndexResult(indexResult); } else return null; } } updateProfiler(iContext, index, keyParams, indexDefinition); return result; }
/** * Returns internal index of last chain index, because proxy applicable to all operations that * last index applicable. */ public OIndexInternal<T> getInternal() { return (OIndexInternal<T>) lastIndex.getInternal(); }
public void commit() { checkTransaction(); status = TXSTATUS.COMMITTING; if (OScenarioThreadLocal.INSTANCE.get() != RUN_MODE.RUNNING_DISTRIBUTED && !(database.getStorage() instanceof OStorageEmbedded)) database.getStorage().commit(this, null); else { final List<String> involvedIndexes = getInvolvedIndexes(); if (involvedIndexes != null) Collections.sort(involvedIndexes); for (int retry = 1; retry <= autoRetries; ++retry) { try { // LOCK INVOLVED INDEXES List<OIndexAbstract<?>> lockedIndexes = null; try { if (involvedIndexes != null) for (String indexName : involvedIndexes) { final OIndexAbstract<?> index = (OIndexAbstract<?>) database.getMetadata().getIndexManager().getIndexInternal(indexName); if (lockedIndexes == null) lockedIndexes = new ArrayList<OIndexAbstract<?>>(); index.acquireModificationLock(); lockedIndexes.add(index); } if (!useSBTree) { // SEARCH FOR INDEX BASED ON DOCUMENT TOUCHED final Collection<? extends OIndex<?>> indexes = database.getMetadata().getIndexManager().getIndexes(); List<? extends OIndex<?>> indexesToLock = null; if (indexes != null) { indexesToLock = new ArrayList<OIndex<?>>(indexes); Collections.sort( indexesToLock, new Comparator<OIndex<?>>() { public int compare(final OIndex<?> indexOne, final OIndex<?> indexTwo) { return indexOne.getName().compareTo(indexTwo.getName()); } }); } if (indexesToLock != null && !indexesToLock.isEmpty()) { if (lockedIndexes == null) lockedIndexes = new ArrayList<OIndexAbstract<?>>(); for (OIndex<?> index : indexesToLock) { for (Entry<ORID, ORecordOperation> entry : recordEntries.entrySet()) { final ORecord<?> record = entry.getValue().record.getRecord(); if (record instanceof ODocument) { ODocument doc = (ODocument) record; if (!lockedIndexes.contains(index.getInternal()) && doc.getSchemaClass() != null && index.getDefinition() != null && doc.getSchemaClass() .isSubClassOf(index.getDefinition().getClassName())) { index.getInternal().acquireModificationLock(); lockedIndexes.add((OIndexAbstract<?>) index.getInternal()); } } } } for (OIndexAbstract<?> index : lockedIndexes) index.acquireExclusiveLock(); } } final Map<String, OIndex> indexes = new HashMap<String, OIndex>(); for (OIndex index : database.getMetadata().getIndexManager().getIndexes()) indexes.put(index.getName(), index); final Runnable callback = new Runnable() { @Override public void run() { final ODocument indexEntries = getIndexChanges(); if (indexEntries != null) { final Map<String, OIndexInternal<?>> indexesToCommit = new HashMap<String, OIndexInternal<?>>(); for (Entry<String, Object> indexEntry : indexEntries) { final OIndexInternal<?> index = indexes.get(indexEntry.getKey()).getInternal(); indexesToCommit.put(index.getName(), index.getInternal()); } for (OIndexInternal<?> indexInternal : indexesToCommit.values()) indexInternal.preCommit(); for (Entry<String, Object> indexEntry : indexEntries) { final OIndexInternal<?> index = indexesToCommit.get(indexEntry.getKey()).getInternal(); if (index == null) { OLogManager.instance() .error( this, "Index with name " + indexEntry.getKey() + " was not found."); throw new OIndexException( "Index with name " + indexEntry.getKey() + " was not found."); } else index.addTxOperation((ODocument) indexEntry.getValue()); } try { for (OIndexInternal<?> indexInternal : indexesToCommit.values()) indexInternal.commit(); } finally { for (OIndexInternal<?> indexInternal : indexesToCommit.values()) indexInternal.postCommit(); } } } }; final String storageType = database.getStorage().getType(); if (storageType.equals(OEngineLocal.NAME) || storageType.equals(OEngineLocalPaginated.NAME)) database.getStorage().commit(OTransactionOptimistic.this, callback); else { database .getStorage() .callInLock( new Callable<Object>() { @Override public Object call() throws Exception { database.getStorage().commit(OTransactionOptimistic.this, null); callback.run(); return null; } }, true); } // OK break; } finally { // RELEASE INDEX LOCKS IF ANY if (lockedIndexes != null) { if (!useSBTree) { for (OIndexAbstract<?> index : lockedIndexes) index.releaseExclusiveLock(); } for (OIndexAbstract<?> index : lockedIndexes) index.releaseModificationLock(); } } } catch (OTimeoutException e) { if (autoRetries == 0) { OLogManager.instance() .debug( this, "Caught timeout exception during commit, but no automatic retry has been set", e); throw e; } else if (retry == autoRetries) { OLogManager.instance() .debug( this, "Caught timeout exception during %d/%d. Retry limit is exceeded.", retry, autoRetries); throw e; } else { OLogManager.instance() .debug( this, "Caught timeout exception during commit retrying %d/%d...", retry, autoRetries); } } } } status = TXSTATUS.COMPLETED; }