Search in sources :

Example 16 with Instant

use of java.time.Instant in project titan by thinkaurelius.

the class SolrIndex method buildQueryFilter.

public String buildQueryFilter(Condition<TitanElement> condition, KeyInformation.StoreRetriever informations) {
    if (condition instanceof PredicateCondition) {
        PredicateCondition<String, TitanElement> atom = (PredicateCondition<String, TitanElement>) condition;
        Object value = atom.getValue();
        String key = atom.getKey();
        TitanPredicate titanPredicate = atom.getPredicate();
        if (value instanceof Number) {
            String queryValue = escapeValue(value);
            Preconditions.checkArgument(titanPredicate instanceof Cmp, "Relation not supported on numeric types: " + titanPredicate);
            Cmp numRel = (Cmp) titanPredicate;
            switch(numRel) {
                case EQUAL:
                    return (key + ":" + queryValue);
                case NOT_EQUAL:
                    return ("-" + key + ":" + queryValue);
                case LESS_THAN:
                    //use right curly to mean up to but not including value
                    return (key + ":[* TO " + queryValue + "}");
                case LESS_THAN_EQUAL:
                    return (key + ":[* TO " + queryValue + "]");
                case GREATER_THAN:
                    //use left curly to mean greater than but not including value
                    return (key + ":{" + queryValue + " TO *]");
                case GREATER_THAN_EQUAL:
                    return (key + ":[" + queryValue + " TO *]");
                default:
                    throw new IllegalArgumentException("Unexpected relation: " + numRel);
            }
        } else if (value instanceof String) {
            Mapping map = getStringMapping(informations.get(key));
            assert map == Mapping.TEXT || map == Mapping.STRING;
            if (map == Mapping.TEXT && !titanPredicate.toString().startsWith("CONTAINS"))
                throw new IllegalArgumentException("Text mapped string values only support CONTAINS queries and not: " + titanPredicate);
            if (map == Mapping.STRING && titanPredicate.toString().startsWith("CONTAINS"))
                throw new IllegalArgumentException("String mapped string values do not support CONTAINS queries: " + titanPredicate);
            //Special case
            if (titanPredicate == Text.CONTAINS) {
                //e.g. - if terms tomorrow and world were supplied, and fq=text:(tomorrow  world)
                //sample data set would return 2 documents: one where text = Tomorrow is the World,
                //and the second where text = Hello World. Hence, we are decomposing the query string
                //and building an AND query explicitly because we need AND semantics
                value = ((String) value).toLowerCase();
                List<String> terms = Text.tokenize((String) value);
                if (terms.isEmpty()) {
                    return "";
                } else if (terms.size() == 1) {
                    return (key + ":(" + escapeValue(terms.get(0)) + ")");
                } else {
                    And<TitanElement> andTerms = new And<TitanElement>();
                    for (String term : terms) {
                        andTerms.add(new PredicateCondition<String, TitanElement>(key, titanPredicate, term));
                    }
                    return buildQueryFilter(andTerms, informations);
                }
            }
            if (titanPredicate == Text.PREFIX || titanPredicate == Text.CONTAINS_PREFIX) {
                return (key + ":" + escapeValue(value) + "*");
            } else if (titanPredicate == Text.REGEX || titanPredicate == Text.CONTAINS_REGEX) {
                return (key + ":/" + value + "/");
            } else if (titanPredicate == Cmp.EQUAL) {
                return (key + ":\"" + escapeValue(value) + "\"");
            } else if (titanPredicate == Cmp.NOT_EQUAL) {
                return ("-" + key + ":\"" + escapeValue(value) + "\"");
            } else {
                throw new IllegalArgumentException("Relation is not supported for string value: " + titanPredicate);
            }
        } else if (value instanceof Geoshape) {
            Geoshape geo = (Geoshape) value;
            if (geo.getType() == Geoshape.Type.CIRCLE) {
                Geoshape.Point center = geo.getPoint();
                return ("{!geofilt sfield=" + key + " pt=" + center.getLatitude() + "," + center.getLongitude() + " d=" + geo.getRadius() + //distance in kilometers
                "} distErrPct=0");
            } else if (geo.getType() == Geoshape.Type.BOX) {
                Geoshape.Point southwest = geo.getPoint(0);
                Geoshape.Point northeast = geo.getPoint(1);
                return (key + ":[" + southwest.getLatitude() + "," + southwest.getLongitude() + " TO " + northeast.getLatitude() + "," + northeast.getLongitude() + "]");
            } else if (geo.getType() == Geoshape.Type.POLYGON) {
                List<Geoshape.Point> coordinates = getPolygonPoints(geo);
                StringBuilder poly = new StringBuilder(key + ":\"IsWithin(POLYGON((");
                for (Geoshape.Point coordinate : coordinates) {
                    poly.append(coordinate.getLongitude()).append(" ").append(coordinate.getLatitude()).append(", ");
                }
                //close the polygon with the first coordinate
                poly.append(coordinates.get(0).getLongitude()).append(" ").append(coordinates.get(0).getLatitude());
                poly.append(")))\" distErrPct=0");
                return (poly.toString());
            }
        } else if (value instanceof Date || value instanceof Instant) {
            String s = value.toString();
            String queryValue = escapeValue(value instanceof Date ? toIsoDate((Date) value) : value.toString());
            Preconditions.checkArgument(titanPredicate instanceof Cmp, "Relation not supported on date types: " + titanPredicate);
            Cmp numRel = (Cmp) titanPredicate;
            switch(numRel) {
                case EQUAL:
                    return (key + ":" + queryValue);
                case NOT_EQUAL:
                    return ("-" + key + ":" + queryValue);
                case LESS_THAN:
                    //use right curly to mean up to but not including value
                    return (key + ":[* TO " + queryValue + "}");
                case LESS_THAN_EQUAL:
                    return (key + ":[* TO " + queryValue + "]");
                case GREATER_THAN:
                    //use left curly to mean greater than but not including value
                    return (key + ":{" + queryValue + " TO *]");
                case GREATER_THAN_EQUAL:
                    return (key + ":[" + queryValue + " TO *]");
                default:
                    throw new IllegalArgumentException("Unexpected relation: " + numRel);
            }
        } else if (value instanceof Boolean) {
            Cmp numRel = (Cmp) titanPredicate;
            String queryValue = escapeValue(value);
            switch(numRel) {
                case EQUAL:
                    return (key + ":" + queryValue);
                case NOT_EQUAL:
                    return ("-" + key + ":" + queryValue);
                default:
                    throw new IllegalArgumentException("Boolean types only support EQUAL or NOT_EQUAL");
            }
        } else if (value instanceof UUID) {
            if (titanPredicate == Cmp.EQUAL) {
                return (key + ":\"" + escapeValue(value) + "\"");
            } else if (titanPredicate == Cmp.NOT_EQUAL) {
                return ("-" + key + ":\"" + escapeValue(value) + "\"");
            } else {
                throw new IllegalArgumentException("Relation is not supported for uuid value: " + titanPredicate);
            }
        } else
            throw new IllegalArgumentException("Unsupported type: " + value);
    } else if (condition instanceof Not) {
        String sub = buildQueryFilter(((Not) condition).getChild(), informations);
        if (StringUtils.isNotBlank(sub))
            return "-(" + sub + ")";
        else
            return "";
    } else if (condition instanceof And) {
        int numChildren = ((And) condition).size();
        StringBuilder sb = new StringBuilder();
        for (Condition<TitanElement> c : condition.getChildren()) {
            String sub = buildQueryFilter(c, informations);
            if (StringUtils.isBlank(sub))
                continue;
            // b. expression is a single statement in the AND.
            if (!sub.startsWith("-") && numChildren > 1)
                sb.append("+");
            sb.append(sub).append(" ");
        }
        return sb.toString();
    } else if (condition instanceof Or) {
        StringBuilder sb = new StringBuilder();
        int element = 0;
        for (Condition<TitanElement> c : condition.getChildren()) {
            String sub = buildQueryFilter(c, informations);
            if (StringUtils.isBlank(sub))
                continue;
            if (element == 0)
                sb.append("(");
            else
                sb.append(" OR ");
            sb.append(sub);
            element++;
        }
        if (element > 0)
            sb.append(")");
        return sb.toString();
    } else {
        throw new IllegalArgumentException("Invalid condition: " + condition);
    }
    return null;
}
Also used : Mapping(com.thinkaurelius.titan.core.schema.Mapping) TitanElement(com.thinkaurelius.titan.core.TitanElement) Instant(java.time.Instant) TitanPredicate(com.thinkaurelius.titan.graphdb.query.TitanPredicate)

Example 17 with Instant

use of java.time.Instant in project titan by thinkaurelius.

the class StandardTitanGraph method commit.

public void commit(final Collection<InternalRelation> addedRelations, final Collection<InternalRelation> deletedRelations, final StandardTitanTx tx) {
    if (addedRelations.isEmpty() && deletedRelations.isEmpty())
        return;
    //1. Finalize transaction
    log.debug("Saving transaction. Added {}, removed {}", addedRelations.size(), deletedRelations.size());
    if (!tx.getConfiguration().hasCommitTime())
        tx.getConfiguration().setCommitTime(times.getTime());
    final Instant txTimestamp = tx.getConfiguration().getCommitTime();
    final long transactionId = txCounter.incrementAndGet();
    //2. Assign TitanVertex IDs
    if (!tx.getConfiguration().hasAssignIDsImmediately())
        idAssigner.assignIDs(addedRelations);
    //3. Commit
    BackendTransaction mutator = tx.getTxHandle();
    final boolean acquireLocks = tx.getConfiguration().hasAcquireLocks();
    final boolean hasTxIsolation = backend.getStoreFeatures().hasTxIsolation();
    final boolean logTransaction = config.hasLogTransactions() && !tx.getConfiguration().hasEnabledBatchLoading();
    final KCVSLog txLog = logTransaction ? backend.getSystemTxLog() : null;
    final TransactionLogHeader txLogHeader = new TransactionLogHeader(transactionId, txTimestamp, times);
    ModificationSummary commitSummary;
    try {
        //3.1 Log transaction (write-ahead log) if enabled
        if (logTransaction) {
            //[FAILURE] Inability to log transaction fails the transaction by escalation since it's likely due to unavailability of primary
            //storage backend.
            txLog.add(txLogHeader.serializeModifications(serializer, LogTxStatus.PRECOMMIT, tx, addedRelations, deletedRelations), txLogHeader.getLogKey());
        }
        //3.2 Commit schema elements and their associated relations in a separate transaction if backend does not support
        //    transactional isolation
        boolean hasSchemaElements = !Iterables.isEmpty(Iterables.filter(deletedRelations, SCHEMA_FILTER)) || !Iterables.isEmpty(Iterables.filter(addedRelations, SCHEMA_FILTER));
        Preconditions.checkArgument(!hasSchemaElements || (!tx.getConfiguration().hasEnabledBatchLoading() && acquireLocks), "Attempting to create schema elements in inconsistent state");
        if (hasSchemaElements && !hasTxIsolation) {
            /*
                 * On storage without transactional isolation, create separate
                 * backend transaction for schema aspects to make sure that
                 * those are persisted prior to and independently of other
                 * mutations in the tx. If the storage supports transactional
                 * isolation, then don't create a separate tx.
                 */
            final BackendTransaction schemaMutator = openBackendTransaction(tx);
            try {
                //[FAILURE] If the preparation throws an exception abort directly - nothing persisted since batch-loading cannot be enabled for schema elements
                commitSummary = prepareCommit(addedRelations, deletedRelations, SCHEMA_FILTER, schemaMutator, tx, acquireLocks);
                assert commitSummary.hasModifications && !commitSummary.has2iModifications;
            } catch (Throwable e) {
                //Roll back schema tx and escalate exception
                schemaMutator.rollback();
                throw e;
            }
            try {
                schemaMutator.commit();
            } catch (Throwable e) {
                //[FAILURE] Primary persistence failed => abort and escalate exception, nothing should have been persisted
                log.error("Could not commit transaction [" + transactionId + "] due to storage exception in system-commit", e);
                throw e;
            }
        }
        //[FAILURE] Exceptions during preparation here cause the entire transaction to fail on transactional systems
        //or just the non-system part on others. Nothing has been persisted unless batch-loading
        commitSummary = prepareCommit(addedRelations, deletedRelations, hasTxIsolation ? NO_FILTER : NO_SCHEMA_FILTER, mutator, tx, acquireLocks);
        if (commitSummary.hasModifications) {
            String logTxIdentifier = tx.getConfiguration().getLogIdentifier();
            boolean hasSecondaryPersistence = logTxIdentifier != null || commitSummary.has2iModifications;
            //    This should not throw an exception since the mutations are just cached. If it does, it will be escalated since its critical
            if (logTransaction) {
                txLog.add(txLogHeader.serializePrimary(serializer, hasSecondaryPersistence ? LogTxStatus.PRIMARY_SUCCESS : LogTxStatus.COMPLETE_SUCCESS), txLogHeader.getLogKey(), mutator.getTxLogPersistor());
            }
            try {
                mutator.commitStorage();
            } catch (Throwable e) {
                //[FAILURE] If primary storage persistence fails abort directly (only schema could have been persisted)
                log.error("Could not commit transaction [" + transactionId + "] due to storage exception in commit", e);
                throw e;
            }
            if (hasSecondaryPersistence) {
                LogTxStatus status = LogTxStatus.SECONDARY_SUCCESS;
                Map<String, Throwable> indexFailures = ImmutableMap.of();
                boolean userlogSuccess = true;
                try {
                    //2. Commit indexes - [FAILURE] all exceptions are collected and logged but nothing is aborted
                    indexFailures = mutator.commitIndexes();
                    if (!indexFailures.isEmpty()) {
                        status = LogTxStatus.SECONDARY_FAILURE;
                        for (Map.Entry<String, Throwable> entry : indexFailures.entrySet()) {
                            log.error("Error while commiting index mutations for transaction [" + transactionId + "] on index: " + entry.getKey(), entry.getValue());
                        }
                    }
                    //3. Log transaction if configured - [FAILURE] is recorded but does not cause exception
                    if (logTxIdentifier != null) {
                        try {
                            userlogSuccess = false;
                            final Log userLog = backend.getUserLog(logTxIdentifier);
                            Future<Message> env = userLog.add(txLogHeader.serializeModifications(serializer, LogTxStatus.USER_LOG, tx, addedRelations, deletedRelations));
                            if (env.isDone()) {
                                try {
                                    env.get();
                                } catch (ExecutionException ex) {
                                    throw ex.getCause();
                                }
                            }
                            userlogSuccess = true;
                        } catch (Throwable e) {
                            status = LogTxStatus.SECONDARY_FAILURE;
                            log.error("Could not user-log committed transaction [" + transactionId + "] to " + logTxIdentifier, e);
                        }
                    }
                } finally {
                    if (logTransaction) {
                        // needs to be cleaned up later
                        try {
                            txLog.add(txLogHeader.serializeSecondary(serializer, status, indexFailures, userlogSuccess), txLogHeader.getLogKey());
                        } catch (Throwable e) {
                            log.error("Could not tx-log secondary persistence status on transaction [" + transactionId + "]", e);
                        }
                    }
                }
            } else {
                //This just closes the transaction since there are no modifications
                mutator.commitIndexes();
            }
        } else {
            //Just commit everything at once
            //[FAILURE] This case only happens when there are no non-system mutations in which case all changes
            //are already flushed. Hence, an exception here is unlikely and should abort
            mutator.commit();
        }
    } catch (Throwable e) {
        log.error("Could not commit transaction [" + transactionId + "] due to exception", e);
        try {
            //Clean up any left-over transaction handles
            mutator.rollback();
        } catch (Throwable e2) {
            log.error("Could not roll-back transaction [" + transactionId + "] after failure due to exception", e2);
        }
        if (e instanceof RuntimeException)
            throw (RuntimeException) e;
        else
            throw new TitanException("Unexpected exception", e);
    }
}
Also used : Message(com.thinkaurelius.titan.diskstorage.log.Message) KCVSLog(com.thinkaurelius.titan.diskstorage.log.kcvs.KCVSLog) KCVSLog(com.thinkaurelius.titan.diskstorage.log.kcvs.KCVSLog) Log(com.thinkaurelius.titan.diskstorage.log.Log) Instant(java.time.Instant) TransactionLogHeader(com.thinkaurelius.titan.graphdb.database.log.TransactionLogHeader) ExecutionException(java.util.concurrent.ExecutionException) LogTxStatus(com.thinkaurelius.titan.graphdb.database.log.LogTxStatus) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 18 with Instant

use of java.time.Instant in project titan by thinkaurelius.

the class ConsistentKeyLocker method writeSingleLock.

/**
     * Try to write a lock record remotely up to the configured number of
     *  times. If the store produces
     * {@link TemporaryLockingException}, then we'll call mutate again to add a
     * new column with an updated timestamp and to delete the column that tried
     * to write when the store threw an exception. We continue like that up to
     * the retry limit. If the store throws anything else, such as an unchecked
     * exception or a {@link com.thinkaurelius.titan.diskstorage.PermanentBackendException}, then we'll try to
     * delete whatever we added and return without further retries.
     *
     * @param lockID lock to acquire
     * @param txh    transaction
     * @return the timestamp, in nanoseconds since UNIX Epoch, on the lock
     *         column that we successfully wrote to the store
     * @throws TemporaryLockingException if the lock retry count is exceeded without successfully
     *                                   writing the lock in less than the wait limit
     * @throws Throwable                 if the storage layer throws anything else
     */
@Override
protected ConsistentKeyLockStatus writeSingleLock(KeyColumn lockID, StoreTransaction txh) throws Throwable {
    final StaticBuffer lockKey = serializer.toLockKey(lockID.getKey(), lockID.getColumn());
    StaticBuffer oldLockCol = null;
    for (int i = 0; i < lockRetryCount; i++) {
        WriteResult wr = tryWriteLockOnce(lockKey, oldLockCol, txh);
        if (wr.isSuccessful() && wr.getDuration().compareTo(lockWait) <= 0) {
            final Instant writeInstant = wr.getWriteTimestamp();
            final Instant expireInstant = writeInstant.plus(lockExpire);
            return new ConsistentKeyLockStatus(writeInstant, expireInstant);
        }
        oldLockCol = wr.getLockCol();
        handleMutationFailure(lockID, lockKey, wr, txh);
    }
    tryDeleteLockOnce(lockKey, oldLockCol, txh);
    // TODO log exception or successful too-slow write here
    throw new TemporaryBackendException("Lock write retry count exceeded");
}
Also used : Instant(java.time.Instant)

Example 19 with Instant

use of java.time.Instant in project titan by thinkaurelius.

the class ConsistentKeyLocker method checkSingleLock.

@Override
protected void checkSingleLock(final KeyColumn kc, final ConsistentKeyLockStatus ls, final StoreTransaction tx) throws BackendException, InterruptedException {
    if (ls.isChecked())
        return;
    // Sleep, if necessary
    // We could be smarter about sleeping by iterating oldest -> latest...
    final Instant now = times.sleepPast(ls.getWriteTimestamp().plus(lockWait));
    // Slice the store
    KeySliceQuery ksq = new KeySliceQuery(serializer.toLockKey(kc.getKey(), kc.getColumn()), LOCK_COL_START, LOCK_COL_END);
    List<Entry> claimEntries = getSliceWithRetries(ksq, tx);
    // Extract timestamp and rid from the column in each returned Entry...
    Iterable<TimestampRid> iter = Iterables.transform(claimEntries, new Function<Entry, TimestampRid>() {

        @Override
        public TimestampRid apply(Entry e) {
            return serializer.fromLockColumn(e.getColumnAs(StaticBuffer.STATIC_FACTORY), times);
        }
    });
    // ...and then filter out the TimestampRid objects with expired timestamps
    // (This doesn't use Iterables.filter and Predicate so that we can throw a checked exception if necessary)
    ArrayList<TimestampRid> unexpiredTRs = new ArrayList<TimestampRid>(Iterables.size(iter));
    for (TimestampRid tr : iter) {
        final Instant cutoffTime = now.minus(lockExpire);
        if (tr.getTimestamp().isBefore(cutoffTime)) {
            log.warn("Discarded expired claim on {} with timestamp {}", kc, tr.getTimestamp());
            if (null != cleanerService)
                cleanerService.clean(kc, cutoffTime, tx);
            // Locks that this instance wrote that have now expired should not only log but also throw a descriptive exception
            if (rid.equals(tr.getRid()) && ls.getWriteTimestamp().equals(tr.getTimestamp())) {
                throw new ExpiredLockException("Expired lock on " + kc.toString() + ": lock timestamp " + tr.getTimestamp() + " " + times.getUnit() + " is older than " + ConfigElement.getPath(GraphDatabaseConfiguration.LOCK_EXPIRE) + "=" + lockExpire);
            // Really shouldn't refer to GDC.LOCK_EXPIRE here, but this will typically be accurate in a real use case
            }
            continue;
        }
        unexpiredTRs.add(tr);
    }
    checkSeniority(kc, ls, unexpiredTRs);
    ls.setChecked();
}
Also used : Instant(java.time.Instant) ArrayList(java.util.ArrayList)

Example 20 with Instant

use of java.time.Instant in project titan by thinkaurelius.

the class ConsistentKeyLockerSerializer method fromLockColumn.

public TimestampRid fromLockColumn(StaticBuffer lockKey, TimestampProvider provider) {
    ReadBuffer r = lockKey.asReadBuffer();
    int len = r.length();
    long tsNS = r.getLong();
    len -= 8;
    byte[] curRid = new byte[len];
    for (int i = 0; r.hasRemaining(); i++) {
        curRid[i] = r.getByte();
    }
    StaticBuffer rid = new StaticArrayBuffer(curRid);
    Instant time = provider.getTime(tsNS);
    return new TimestampRid(time, rid);
}
Also used : ReadBuffer(com.thinkaurelius.titan.diskstorage.ReadBuffer) Instant(java.time.Instant) StaticArrayBuffer(com.thinkaurelius.titan.diskstorage.util.StaticArrayBuffer) StaticBuffer(com.thinkaurelius.titan.diskstorage.StaticBuffer)

Aggregations

Instant (java.time.Instant)463 Test (org.testng.annotations.Test)143 Test (org.junit.Test)85 ZonedDateTime (java.time.ZonedDateTime)39 Duration (java.time.Duration)30 Clock (java.time.Clock)26 Lifetime (org.apache.cxf.sts.request.Lifetime)26 OffsetDateTime (java.time.OffsetDateTime)23 LocalDateTime (java.time.LocalDateTime)20 ArrayList (java.util.ArrayList)18 Element (org.w3c.dom.Element)18 LocalDate (java.time.LocalDate)17 IOException (java.io.IOException)14 Date (java.util.Date)14 LocalTime (java.time.LocalTime)12 DateTimeFormatter (java.time.format.DateTimeFormatter)12 STSException (org.apache.cxf.ws.security.sts.provider.STSException)12 SecurityToken (org.apache.cxf.ws.security.tokenstore.SecurityToken)12 Timestamp (java.sql.Timestamp)11 DefaultConditionsProvider (org.apache.cxf.sts.token.provider.DefaultConditionsProvider)10