Search in sources :

Example 1 with Key

use of com.cinchapi.concourse.validate.Keys.Key in project concourse by cinchapi.

the class Stores method serialSelect.

/**
 * Select the values stored for {@code key} in {@code record} at
 * {@code timestamp} from the {@code store}.
 * <p>
 * If the {@code key} is primitive, the store retrieval is usually a simple
 * {@link Store#select(long) select}. However, if the key is a navigation
 * key, this method will process it via
 * {@link Operations#traverseKeyRecordOptionalAtomic(String, long, long, AtomicOperation)}
 * if the {@code store} is an {@link AtomicOperation} or
 * {@link AtomicSupport supports} starting one.
 * </p>
 *
 * @param store
 * @param key
 * @param record
 * @param timestamp
 *
 * @return the values stored for {@code key} in {@code record} at
 *         {@code timestamp} according to the {@code store}
 */
protected static Set<TObject> serialSelect(Store store, String key, long record, long timestamp) {
    Function evalFunc;
    if (Keys.isNavigationKey(key)) {
        if (store instanceof AtomicOperation || timestamp != Time.NONE) {
            return Operations.traverseKeyRecordOptionalAtomic(key, record, timestamp, store);
        } else if (store instanceof AtomicSupport) {
            AtomicReference<Set<TObject>> value = new AtomicReference<>(ImmutableSet.of());
            AtomicOperations.executeWithRetry((AtomicSupport) store, (atomic) -> {
                value.set(Operations.traverseKeyRecordOptionalAtomic(key, record, timestamp, atomic));
            });
            return value.get();
        } else {
            throw new UnsupportedOperationException("Cannot fetch the current values of a navigation key using a Store that does not support atomic operations");
        }
    } else if ((evalFunc = Keys.tryParseFunction(key)) != null) {
        String method = Calculations.alias(evalFunc.operation()) + "KeyRecordAtomic";
        Number value = Reflection.callStatic(Operations.class, method, evalFunc.key(), record, timestamp, store);
        return value != null ? ImmutableSet.of(Convert.javaToThrift(value)) : ImmutableSet.of();
    } else if (key.equals(Constants.JSON_RESERVED_IDENTIFIER_NAME)) {
        return ImmutableSet.of(Convert.javaToThrift(record));
    } else {
        Source source;
        if (Command.isSet()) {
            Strategy strategy = new Strategy(Command.current(), store);
            source = strategy.source(key, record);
        } else {
            source = Source.FIELD;
        }
        Set<TObject> values;
        if (source == Source.RECORD) {
            // @formatter:off
            Map<String, Set<TObject>> data = timestamp == Time.NONE ? store.select(record) : store.select(record, timestamp);
            values = data.getOrDefault(key, ImmutableSet.of());
        // @formatter:on
        } else if (source == Source.FIELD) {
            // @formatter:off
            values = timestamp == Time.NONE ? store.select(key, record) : store.select(key, record, timestamp);
        // @formatter:on
        } else {
            // source == Source.INDEX
            // @formatter:off
            values = timestamp == Time.NONE ? store.gather(key, record) : store.gather(key, record, timestamp);
        // @formatter:on
        }
        return values;
    }
}
Also used : Function(com.cinchapi.ccl.type.Function) ArrayBuilder(com.cinchapi.common.base.ArrayBuilder) Source(com.cinchapi.concourse.server.ops.Strategy.Source) Store(com.cinchapi.concourse.server.storage.Store) AbstractSet(java.util.AbstractSet) AdHocIterator(com.cinchapi.common.base.AdHocIterator) HashMap(java.util.HashMap) IndexFunction(com.cinchapi.ccl.type.function.IndexFunction) Constants(com.cinchapi.concourse.Constants) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Calculations(com.cinchapi.concourse.server.calculate.Calculations) Reflection(com.cinchapi.common.reflect.Reflection) AtomicSupport(com.cinchapi.concourse.server.storage.AtomicSupport) ImmutableList(com.google.common.collect.ImmutableList) TObject(com.cinchapi.concourse.thrift.TObject) Convert(com.cinchapi.concourse.util.Convert) Keys(com.cinchapi.concourse.validate.Keys) TemporalFunction(com.cinchapi.ccl.type.function.TemporalFunction) Map(java.util.Map) Link(com.cinchapi.concourse.Link) LinkedHashSet(java.util.LinkedHashSet) Nullable(javax.annotation.Nullable) KeyType(com.cinchapi.concourse.validate.Keys.KeyType) Time(com.cinchapi.concourse.time.Time) ImmutableSet(com.google.common.collect.ImmutableSet) Iterator(java.util.Iterator) ImmutableMap(com.google.common.collect.ImmutableMap) Collection(java.util.Collection) Set(java.util.Set) KeyConditionFunction(com.cinchapi.ccl.type.function.KeyConditionFunction) MoreObjects(com.google.common.base.MoreObjects) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) AtomicOperation(com.cinchapi.concourse.server.storage.AtomicOperation) Operator(com.cinchapi.concourse.thrift.Operator) ForwardingMap(com.google.common.collect.ForwardingMap) Finder(com.cinchapi.concourse.server.query.Finder) Key(com.cinchapi.concourse.validate.Keys.Key) Type(com.cinchapi.concourse.thrift.Type) Queue(java.util.Queue) ArrayDeque(java.util.ArrayDeque) KeyValue(com.cinchapi.concourse.util.KeyValue) KeyRecordsFunction(com.cinchapi.ccl.type.function.KeyRecordsFunction) TObject(com.cinchapi.concourse.thrift.TObject) AbstractSet(java.util.AbstractSet) LinkedHashSet(java.util.LinkedHashSet) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) AtomicSupport(com.cinchapi.concourse.server.storage.AtomicSupport) AtomicReference(java.util.concurrent.atomic.AtomicReference) Source(com.cinchapi.concourse.server.ops.Strategy.Source) Function(com.cinchapi.ccl.type.Function) IndexFunction(com.cinchapi.ccl.type.function.IndexFunction) TemporalFunction(com.cinchapi.ccl.type.function.TemporalFunction) KeyConditionFunction(com.cinchapi.ccl.type.function.KeyConditionFunction) KeyRecordsFunction(com.cinchapi.ccl.type.function.KeyRecordsFunction) AtomicOperation(com.cinchapi.concourse.server.storage.AtomicOperation)

Example 2 with Key

use of com.cinchapi.concourse.validate.Keys.Key in project concourse by cinchapi.

the class Stores method find.

/**
 * Find the records that contain values that are stored for {@code key} and
 * satisfy {@code operator} in relation to the specified {@code values} at
 * {@code timestamp}.
 * <p>
 * If the {@code key} is primitive, the store lookup is usually a simple
 * {@link Store#find(String, Operator, TObject[]) find}. However, if the key
 * is a navigation key, this method will process it by
 * {@link #browse(Store, String) browsing} the destination values and
 * checking the operator validity of each if and only if the {@code store}
 * is an {@link AtomicOperation} or {@link AtomicSupport supports} starting
 * one.
 * </p>
 *
 * @param store
 * @param timestamp
 * @param key
 * @param operator
 * @param values
 * @return the records that satisfy the query
 */
public static Set<Long> find(Store store, long timestamp, String key, Operator operator, TObject... values) {
    for (int i = 0; i < values.length; ++i) {
        TObject value = values[i];
        if (value.getType() == Type.FUNCTION) {
            Function function = (Function) Convert.thriftToJava(value);
            TemporalFunction func = (TemporalFunction) function;
            String method = Calculations.alias(function.operation());
            ArrayBuilder<Object> args = ArrayBuilder.builder();
            method += "Key";
            args.add(function.key());
            if (function instanceof KeyRecordsFunction || function instanceof KeyConditionFunction) {
                method += "Records";
                Collection<Long> records = function instanceof KeyRecordsFunction ? ((KeyRecordsFunction) function).source() : Finder.instance().visit(((KeyConditionFunction) function).source(), store);
                args.add(records);
            } else if (!(function instanceof IndexFunction)) {
                throw new IllegalStateException("Invalid function value");
            }
            method += "Atomic";
            args.add(func.timestamp());
            args.add(store);
            values[i] = Convert.javaToThrift(Reflection.callStatic(Operations.class, method, args.build()));
        }
    }
    if (Keys.isNavigationKey(key)) {
        Map<TObject, Set<Long>> index = timestamp == Time.NONE ? browse(store, key) : browse(store, key, timestamp);
        Set<Long> records = index.entrySet().stream().filter(e -> e.getKey().is(operator, values)).map(e -> e.getValue()).flatMap(Set::stream).collect(Collectors.toCollection(LinkedHashSet::new));
        return records;
    } else if (Keys.isFunctionKey(key)) {
        Set<Long> records = Sets.newLinkedHashSet();
        for (long record : store.getAllRecords()) {
            Set<TObject> aggregate = select(store, key, record, timestamp);
            for (TObject tobject : aggregate) {
                if (tobject.is(operator, values)) {
                    records.add(record);
                    break;
                }
            }
        }
        return records;
    } else {
        return timestamp == Time.NONE ? store.find(key, operator, values) : store.find(timestamp, key, operator, values);
    }
}
Also used : Function(com.cinchapi.ccl.type.Function) ArrayBuilder(com.cinchapi.common.base.ArrayBuilder) Source(com.cinchapi.concourse.server.ops.Strategy.Source) Store(com.cinchapi.concourse.server.storage.Store) AbstractSet(java.util.AbstractSet) AdHocIterator(com.cinchapi.common.base.AdHocIterator) HashMap(java.util.HashMap) IndexFunction(com.cinchapi.ccl.type.function.IndexFunction) Constants(com.cinchapi.concourse.Constants) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Calculations(com.cinchapi.concourse.server.calculate.Calculations) Reflection(com.cinchapi.common.reflect.Reflection) AtomicSupport(com.cinchapi.concourse.server.storage.AtomicSupport) ImmutableList(com.google.common.collect.ImmutableList) TObject(com.cinchapi.concourse.thrift.TObject) Convert(com.cinchapi.concourse.util.Convert) Keys(com.cinchapi.concourse.validate.Keys) TemporalFunction(com.cinchapi.ccl.type.function.TemporalFunction) Map(java.util.Map) Link(com.cinchapi.concourse.Link) LinkedHashSet(java.util.LinkedHashSet) Nullable(javax.annotation.Nullable) KeyType(com.cinchapi.concourse.validate.Keys.KeyType) Time(com.cinchapi.concourse.time.Time) ImmutableSet(com.google.common.collect.ImmutableSet) Iterator(java.util.Iterator) ImmutableMap(com.google.common.collect.ImmutableMap) Collection(java.util.Collection) Set(java.util.Set) KeyConditionFunction(com.cinchapi.ccl.type.function.KeyConditionFunction) MoreObjects(com.google.common.base.MoreObjects) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) AtomicOperation(com.cinchapi.concourse.server.storage.AtomicOperation) Operator(com.cinchapi.concourse.thrift.Operator) ForwardingMap(com.google.common.collect.ForwardingMap) Finder(com.cinchapi.concourse.server.query.Finder) Key(com.cinchapi.concourse.validate.Keys.Key) Type(com.cinchapi.concourse.thrift.Type) Queue(java.util.Queue) ArrayDeque(java.util.ArrayDeque) KeyValue(com.cinchapi.concourse.util.KeyValue) KeyRecordsFunction(com.cinchapi.ccl.type.function.KeyRecordsFunction) TObject(com.cinchapi.concourse.thrift.TObject) AbstractSet(java.util.AbstractSet) LinkedHashSet(java.util.LinkedHashSet) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) KeyRecordsFunction(com.cinchapi.ccl.type.function.KeyRecordsFunction) TemporalFunction(com.cinchapi.ccl.type.function.TemporalFunction) Function(com.cinchapi.ccl.type.Function) IndexFunction(com.cinchapi.ccl.type.function.IndexFunction) TemporalFunction(com.cinchapi.ccl.type.function.TemporalFunction) KeyConditionFunction(com.cinchapi.ccl.type.function.KeyConditionFunction) KeyRecordsFunction(com.cinchapi.ccl.type.function.KeyRecordsFunction) IndexFunction(com.cinchapi.ccl.type.function.IndexFunction) TObject(com.cinchapi.concourse.thrift.TObject) KeyConditionFunction(com.cinchapi.ccl.type.function.KeyConditionFunction)

Example 3 with Key

use of com.cinchapi.concourse.validate.Keys.Key in project concourse by cinchapi.

the class KeysTest method testParseWritableKey.

@Test
public void testParseWritableKey() {
    String input = Random.getSimpleString();
    Key key = Keys.parse(input);
    Assert.assertEquals(KeyType.WRITABLE_KEY, key.type());
}
Also used : Key(com.cinchapi.concourse.validate.Keys.Key) Test(org.junit.Test)

Example 4 with Key

use of com.cinchapi.concourse.validate.Keys.Key in project concourse by cinchapi.

the class KeysTest method testParseNavigationKey.

@Test
public void testParseNavigationKey() {
    ArrayBuilder<String> ab = ArrayBuilder.builder();
    for (int i = 0; i < Random.getScaleCount(); ++i) {
        ab.add(Random.getSimpleString());
    }
    String input = AnyStrings.join('.', (Object[]) ab.build());
    Key key = Keys.parse(input);
    Assert.assertEquals(KeyType.NAVIGATION_KEY, key.type());
    Assert.assertArrayEquals(ab.build(), key.data());
}
Also used : Key(com.cinchapi.concourse.validate.Keys.Key) Test(org.junit.Test)

Example 5 with Key

use of com.cinchapi.concourse.validate.Keys.Key in project concourse by cinchapi.

the class Stores method select.

/**
 * Select all of the {@code keys} from {@code record} at {@code timestamp}
 * within {@code store}.
 * <p>
 * This method contains optimizations to efficiently select multiple keys
 * from a record with as few lookups as possible; especially if there are
 * multiple {@link KeyType#NAVIGATION_KEY navigation keys}.
 * </p>
 *
 * @param store
 * @param keys
 * @param record
 * @param timestamp
 * @return a mapping from each of the {@code keys} to the data held for it
 *         in {@code record} at {@code timestamp} within {@code store}
 */
public static Map<String, Set<TObject>> select(Store store, Collection<String> keys, long record, long timestamp) {
    if (keys.isEmpty()) {
        return ImmutableMap.of();
    } else {
        Map<String, Set<TObject>> data = new HashMap<>(keys.size());
        Map<String, Set<TObject>> stored = null;
        Node root = null;
        int count = 1;
        for (String key : keys) {
            Key metadata = Keys.parse(key);
            KeyType type = metadata.type();
            if (type == KeyType.NAVIGATION_KEY) {
                // Generate a single Graph containing all of the stops in
                // each of the navigation keys.
                root = root == null ? Node.root(record) : root;
                Node node = root;
                String[] stops = metadata.data();
                for (String stop : stops) {
                    node = node.next(stop);
                    ++count;
                }
                node.end();
            } else {
                Set<TObject> values;
                if (type == KeyType.WRITABLE_KEY && keys.size() == 1) {
                    // efficient lookup source.
                    return ImmutableMap.of(key, lookupWithStrategy(store, key, record, timestamp));
                } else if (type == KeyType.WRITABLE_KEY) {
                    // @formatter:off
                    stored = stored == null ? (timestamp == Time.NONE ? store.select(record) : store.select(record, timestamp)) : stored;
                    // @formatter:on
                    values = stored.get(key);
                    if (values == null) {
                        values = ImmutableSet.of();
                    }
                } else if (type == KeyType.IDENTIFIER_KEY) {
                    values = ImmutableSet.of(Convert.javaToThrift(record));
                } else if (type == KeyType.FUNCTION_KEY) {
                    Function function = metadata.data();
                    String method = Calculations.alias(function.operation()) + "KeyRecordAtomic";
                    Number value = Reflection.callStatic(Operations.class, method, function.key(), record, timestamp, store);
                    values = value != null ? ImmutableSet.of(Convert.javaToThrift(value)) : ImmutableSet.of();
                } else {
                    values = ImmutableSet.of();
                }
                data.put(key, values);
            }
        }
        if (root != null) {
            // Iterate through the graph, in a breadth-first manner, to
            // perform bulk selection at each Junctions.
            Queue<Node> queue = new ArrayDeque<>(count);
            queue.add(root);
            while (!queue.isEmpty()) {
                Node node = queue.poll();
                Collection<Node> successors = node.successors();
                if (successors.isEmpty()) {
                    data.put(node.path, node.values());
                } else {
                    queue.addAll(successors);
                    Collection<Long> links = node.links();
                    for (long link : links) {
                        Map<String, Set<TObject>> intermediate = null;
                        if (successors.size() > 1) {
                            // Bypassing the Strategy framework is
                            // acceptable here because we know that there
                            // are multiple keys that need to be selected
                            // from each record, so it makes sense to select
                            // the entire record from the Engine, once
                            intermediate = timestamp == Time.NONE ? store.select(link) : store.select(link, timestamp);
                        }
                        for (Node successor : successors) {
                            String stop = successor.stop;
                            if (intermediate == null) {
                                // This means there is only 1 successor, so
                                // the lookup should defer to the Strategy
                                // framework
                                intermediate = ImmutableMap.of(stop, lookupWithStrategy(store, stop, link, timestamp));
                            }
                            Set<TObject> values = intermediate.get(stop);
                            if (values != null) {
                                successor.store(values);
                            } else if (stop.equals(Constants.JSON_RESERVED_IDENTIFIER_NAME)) {
                                successor.store(Convert.javaToThrift(link));
                            }
                        }
                    }
                }
            }
        }
        return data.size() > 1 ? new OrderImposingMap<>(keys, data) : data;
    }
}
Also used : TObject(com.cinchapi.concourse.thrift.TObject) AbstractSet(java.util.AbstractSet) LinkedHashSet(java.util.LinkedHashSet) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) KeyType(com.cinchapi.concourse.validate.Keys.KeyType) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayDeque(java.util.ArrayDeque) Function(com.cinchapi.ccl.type.Function) IndexFunction(com.cinchapi.ccl.type.function.IndexFunction) TemporalFunction(com.cinchapi.ccl.type.function.TemporalFunction) KeyConditionFunction(com.cinchapi.ccl.type.function.KeyConditionFunction) KeyRecordsFunction(com.cinchapi.ccl.type.function.KeyRecordsFunction) Key(com.cinchapi.concourse.validate.Keys.Key)

Aggregations

Key (com.cinchapi.concourse.validate.Keys.Key)7 Function (com.cinchapi.ccl.type.Function)3 IndexFunction (com.cinchapi.ccl.type.function.IndexFunction)3 KeyConditionFunction (com.cinchapi.ccl.type.function.KeyConditionFunction)3 KeyRecordsFunction (com.cinchapi.ccl.type.function.KeyRecordsFunction)3 TemporalFunction (com.cinchapi.ccl.type.function.TemporalFunction)3 TObject (com.cinchapi.concourse.thrift.TObject)3 KeyType (com.cinchapi.concourse.validate.Keys.KeyType)3 ImmutableSet (com.google.common.collect.ImmutableSet)3 AbstractSet (java.util.AbstractSet)3 ArrayDeque (java.util.ArrayDeque)3 HashMap (java.util.HashMap)3 LinkedHashMap (java.util.LinkedHashMap)3 LinkedHashSet (java.util.LinkedHashSet)3 AdHocIterator (com.cinchapi.common.base.AdHocIterator)2 ArrayBuilder (com.cinchapi.common.base.ArrayBuilder)2 Reflection (com.cinchapi.common.reflect.Reflection)2 Constants (com.cinchapi.concourse.Constants)2 Link (com.cinchapi.concourse.Link)2 Calculations (com.cinchapi.concourse.server.calculate.Calculations)2