Search in sources :

Example 1 with KeyPathNode

use of org.apache.ignite.internal.configuration.direct.KeyPathNode in project ignite-3 by apache.

the class ConfigurationUtil method findEx.

/**
 * Finds a node or a leaf by the given path.
 *
 * @param path     Path.
 * @param rootNode Root node.
 * @param <T>      Arbitrary result type.
 * @return Node or leaf.
 */
@Nullable
public static <T> T findEx(List<KeyPathNode> path, InnerNode rootNode) {
    try {
        var visitor = new ConfigurationVisitor<T>() {

            private final int pathSize = path.size();

            /**
             * Current index of the key in the {@code path}.
             */
            private int idx;

            /**
             * {@inheritDoc}
             */
            @Override
            public T visitLeafNode(String key, Serializable val) {
                if (idx != pathSize) {
                    throw new KeyNotFoundException("Configuration value '" + joinPath(path.subList(0, idx)) + "' is a leaf");
                } else {
                    return (T) val;
                }
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public T visitInnerNode(String key, InnerNode node) {
                if (node == null) {
                    throw new KeyNotFoundException("Configuration node '" + joinPath(path.subList(0, idx)) + "' is null");
                } else if (idx == pathSize) {
                    return (T) node;
                } else {
                    try {
                        KeyPathNode pathNode = path.get(idx++);
                        assert !pathNode.unresolvedName;
                        if (INTERNAL_ID.equals(pathNode.key)) {
                            // It's impossible to get this value with a regular traversal. Just call a method.
                            return (T) node.internalId();
                        } else if (INJECTED_NAME.equals(pathNode.key)) {
                            // It's impossible to get this value with a regular traversal. Just call a method.
                            return (T) node.getInjectedNameFieldValue();
                        }
                        return node.traverseChild(pathNode.key, this, true);
                    } catch (NoSuchElementException e) {
                        throw new KeyNotFoundException("Configuration value '" + joinPath(path.subList(0, idx)) + "' has not been found");
                    } catch (ConfigurationWrongPolymorphicTypeIdException e) {
                        assert false : e;
                        return null;
                    }
                }
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public T visitNamedListNode(String key, NamedListNode<?> node) {
                if (idx == pathSize) {
                    return (T) node;
                } else {
                    KeyPathNode pathNode = path.get(idx++);
                    assert pathNode.namedListEntry;
                    String name = pathNode.unresolvedName ? pathNode.key : node.keyByInternalId(UUID.fromString(pathNode.key));
                    return visitInnerNode(name, node.getInnerNode(name));
                }
            }
        };
        return rootNode.accept(null, visitor);
    } catch (KeyNotFoundException e) {
        throw new NoSuchElementException(joinPath(path));
    }
}
Also used : Serializable(java.io.Serializable) NamedListNode(org.apache.ignite.internal.configuration.tree.NamedListNode) ConfigurationWrongPolymorphicTypeIdException(org.apache.ignite.configuration.ConfigurationWrongPolymorphicTypeIdException) ConfigurationVisitor(org.apache.ignite.internal.configuration.tree.ConfigurationVisitor) KeyPathNode(org.apache.ignite.internal.configuration.direct.KeyPathNode) NoSuchElementException(java.util.NoSuchElementException) InnerNode(org.apache.ignite.internal.configuration.tree.InnerNode) Nullable(org.jetbrains.annotations.Nullable)

Example 2 with KeyPathNode

use of org.apache.ignite.internal.configuration.direct.KeyPathNode in project ignite-3 by apache.

the class DirectProxyAsmGenerator method addGetMethod.

/**
 * Generates getter based on the field.
 */
private void addGetMethod(Field schemaField) {
    Class<?> schemaFieldType = schemaField.getType();
    String fieldName = schemaField.getName();
    SchemaClassesInfo schemaClassInfo = cgen.schemaInfo(schemaFieldType);
    ParameterizedType returnType;
    // Return type is determined like in ConfigurationImpl class.
    if (isConfigValue(schemaField)) {
        returnType = typeFromJavaClassName(schemaClassInfo.cfgClassName);
    } else if (isNamedConfigValue(schemaField)) {
        returnType = type(NamedConfigurationTree.class);
    } else {
        assert isValue(schemaField) || isPolymorphicId(schemaField) || isInjectedName(schemaField) || isInternalId(schemaField) : schemaField;
        returnType = type(ConfigurationValue.class);
    }
    MethodDefinition methodDef = classDef.declareMethod(of(PUBLIC), fieldName, returnType);
    BytecodeBlock body = methodDef.getBody();
    if (isValue(schemaField) || isPolymorphicId(schemaField) || isInjectedName(schemaField) || isInternalId(schemaField)) {
        // new DirectValueProxy(appendKey(this.keys, new KeyPathNode("name")), changer);
        // or
        // new DirectValueProxy(appendKey(this.keys, new KeyPathNode("<internal_id>")), changer);
        body.append(newInstance(DirectValueProxy.class, invokeStatic(APPEND_KEY, methodDef.getThis().getField("keys", List.class), newInstance(KeyPathNode.class, constantString(isInjectedName(schemaField) ? InnerNode.INJECTED_NAME : isInternalId(schemaField) ? InnerNode.INTERNAL_ID : fieldName))), methodDef.getThis().getField("changer", DynamicConfigurationChanger.class)));
    } else {
        SchemaClassesInfo fieldSchemaClassInfo = cgen.schemaInfo(schemaField.getType());
        ParameterizedType resultType = typeFromJavaClassName(fieldSchemaClassInfo.directProxyClassName);
        if (isConfigValue(schemaField)) {
            // new BarDirectProxy(appendKey(this.keys, new KeyPathNode("name")), changer);
            body.append(newInstance(resultType, invokeStatic(APPEND_KEY, methodDef.getThis().getField("keys", List.class), newInstance(KeyPathNode.class, constantString(fieldName))), methodDef.getThis().getField("changer", DynamicConfigurationChanger.class)));
        } else {
            // new DirectNamedListProxy(appendKey(this.keys, new KeyPathNode("name")), changer, BarDirectProxy::new);
            body.append(newInstance(DirectNamedListProxy.class, invokeStatic(APPEND_KEY, methodDef.getThis().getField("keys", List.class), newInstance(KeyPathNode.class, constantString(fieldName))), methodDef.getThis().getField("changer", DynamicConfigurationChanger.class), newDirectProxyLambda(fieldSchemaClassInfo)));
        }
    }
    // Return object from the above.
    body.retObject();
}
Also used : ParameterizedType(com.facebook.presto.bytecode.ParameterizedType) MethodDefinition(com.facebook.presto.bytecode.MethodDefinition) BytecodeBlock(com.facebook.presto.bytecode.BytecodeBlock) DirectValueProxy(org.apache.ignite.internal.configuration.direct.DirectValueProxy) Arrays.asList(java.util.Arrays.asList) List(java.util.List) BytecodeExpressions.constantString(com.facebook.presto.bytecode.expression.BytecodeExpressions.constantString) KeyPathNode(org.apache.ignite.internal.configuration.direct.KeyPathNode) DirectNamedListProxy(org.apache.ignite.internal.configuration.direct.DirectNamedListProxy)

Example 3 with KeyPathNode

use of org.apache.ignite.internal.configuration.direct.KeyPathNode in project ignite-3 by apache.

the class ConfigurationChanger method getLatest.

/**
 * {@inheritDoc}
 */
@Override
public <T> T getLatest(List<KeyPathNode> path) {
    assert !path.isEmpty();
    assert path instanceof RandomAccess : path.getClass();
    assert !path.get(0).unresolvedName : path;
    // This map will be merged into the data from the storage. It's required for the conversion into tree to work.
    // Namely, named list order indexes and names are mandatory for conversion.
    Map<String, Map<String, Serializable>> extras = new HashMap<>();
    // Joiner for the prefix that will be used to fetch data from the storage.
    StringJoiner prefixJoiner = new StringJoiner(KEY_SEPARATOR);
    int pathSize = path.size();
    KeyPathNode lastPathNode = path.get(pathSize - 1);
    // This loop is required to accumulate prefix and resolve all unresolved named list elements' ids.
    for (int idx = 0; idx < pathSize; idx++) {
        KeyPathNode keyPathNode = path.get(idx);
        // Regular keys and resolved ids go straight to the prefix.
        if (!keyPathNode.unresolvedName) {
            // Fake name and 0 index go to extras in case of resolved named list elements.
            if (keyPathNode.namedListEntry) {
                prefixJoiner.add(escape(keyPathNode.key));
                String prefix = prefixJoiner + KEY_SEPARATOR;
                extras.put(prefix, Map.of(prefix + NamedListNode.NAME, "<name_placeholder>", prefix + NamedListNode.ORDER_IDX, 0));
            } else {
                prefixJoiner.add(keyPathNode.key);
            }
            continue;
        }
        assert keyPathNode.namedListEntry : path;
        // Here we have unresolved named list element. Name must be translated into the internal id.
        // There's a special path for this purpose in the storage.
        String unresolvedNameKey = prefixJoiner + KEY_SEPARATOR + NamedListNode.IDS + KEY_SEPARATOR + escape(keyPathNode.key);
        // Data from the storage.
        Serializable resolvedName = storage.readLatest(unresolvedNameKey);
        if (resolvedName == null) {
            throw new NoSuchElementException(prefixJoiner + KEY_SEPARATOR + escape(keyPathNode.key));
        }
        assert resolvedName instanceof String : resolvedName;
        // Resolved internal id from the map.
        String internalId = (String) resolvedName;
        // `*.get("resourceName").internalId()` then the result can be returned straight away.
        if (idx == pathSize - 2 && INTERNAL_ID.equals(lastPathNode.key)) {
            assert !lastPathNode.unresolvedName : path;
            // Despite the fact that this cast looks very stupid, it is correct. Internal ids are always UUIDs.
            return (T) UUID.fromString(internalId);
        }
        prefixJoiner.add(internalId);
        String prefix = prefixJoiner + KEY_SEPARATOR;
        // Real name and 0 index go to extras in case of unresolved named list elements.
        extras.put(prefix, Map.of(prefix + NamedListNode.NAME, keyPathNode.key, prefix + NamedListNode.ORDER_IDX, 0));
    }
    // That id must be resolved, otherwise method would already be completed in the loop above.
    if (lastPathNode.key.equals(INTERNAL_ID) && !lastPathNode.unresolvedName && path.get(pathSize - 2).namedListEntry) {
        assert !path.get(pathSize - 2).unresolvedName : path;
        // Not very elegant, I know. <internal_id> is replaced with the <name> in the prefix.
        // <name> always exists in named list element, and it's an easy way to check element's existence.
        String nameStorageKey = prefixJoiner.toString().replaceAll(quote(INTERNAL_ID) + "$", NamedListNode.NAME);
        // Data from the storage.
        Serializable name = storage.readLatest(nameStorageKey);
        if (name != null) {
            // Id is already known.
            return (T) UUID.fromString(path.get(pathSize - 2).key);
        } else {
            throw new NoSuchElementException(prefixJoiner.toString());
        }
    }
    String prefix = prefixJoiner.toString();
    if (lastPathNode.key.equals(INTERNAL_ID) && !path.get(pathSize - 2).namedListEntry) {
        // This is not particularly efficient, but there's no way someone will actually use this case for real outside of tests.
        prefix = prefix.replaceAll(quote(KEY_SEPARATOR + INTERNAL_ID) + "$", "");
    } else if (lastPathNode.key.contains(INJECTED_NAME)) {
        prefix = prefix.replaceAll(quote(KEY_SEPARATOR + INJECTED_NAME), "");
    }
    // Data from the storage.
    Map<String, ? extends Serializable> storageData = storage.readAllLatest(prefix);
    // Data to be converted into the tree.
    Map<String, Serializable> mergedData = new HashMap<>();
    if (!storageData.isEmpty()) {
        mergedData.putAll(storageData);
        for (Entry<String, Map<String, Serializable>> extrasEntry : extras.entrySet()) {
            for (String storageKey : storageData.keySet()) {
                String extrasPrefix = extrasEntry.getKey();
                if (storageKey.startsWith(extrasPrefix)) {
                    // Add extra order indexes and names before converting it to the tree.
                    for (Entry<String, Serializable> extrasEntryMap : extrasEntry.getValue().entrySet()) {
                        mergedData.putIfAbsent(extrasEntryMap.getKey(), extrasEntryMap.getValue());
                    }
                    break;
                }
            }
        }
        if (lastPathNode.namedListEntry) {
            // Change element's order index to zero. Conversion won't work if indexes range is not continuous.
            mergedData.put(prefix + KEY_SEPARATOR + NamedListNode.ORDER_IDX, 0);
        }
    }
    // Super root that'll be filled from the storage data.
    InnerNode rootNode = new SuperRoot(rootCreator());
    fillFromPrefixMap(rootNode, toPrefixMap(mergedData));
    // "addDefaults" won't work if regular root is missing.
    if (storageData.isEmpty()) {
        rootNode.construct(path.get(0).key, ConfigurationUtil.EMPTY_CFG_SRC, true);
    }
    addDefaults(rootNode);
    return findEx(path, rootNode);
}
Also used : Serializable(java.io.Serializable) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) RandomAccess(java.util.RandomAccess) InnerNode(org.apache.ignite.internal.configuration.tree.InnerNode) KeyPathNode(org.apache.ignite.internal.configuration.direct.KeyPathNode) Collectors.toMap(java.util.stream.Collectors.toMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ConfigurationUtil.fillFromPrefixMap(org.apache.ignite.internal.configuration.util.ConfigurationUtil.fillFromPrefixMap) ConfigurationFlattener.createFlattenedUpdatesMap(org.apache.ignite.internal.configuration.util.ConfigurationFlattener.createFlattenedUpdatesMap) HashMap(java.util.HashMap) ConfigurationUtil.toPrefixMap(org.apache.ignite.internal.configuration.util.ConfigurationUtil.toPrefixMap) StringJoiner(java.util.StringJoiner) NoSuchElementException(java.util.NoSuchElementException)

Example 4 with KeyPathNode

use of org.apache.ignite.internal.configuration.direct.KeyPathNode in project ignite-3 by apache.

the class ConfigurationNode method keyPath.

/**
 * Converts {@link #keys} into a list of {@link KeyPathNode}. Result is used in implementations of {@link DirectPropertyProxy}.
 */
protected final List<KeyPathNode> keyPath() {
    if (listenOnly) {
        throw listenOnlyException();
    }
    ConfigurationVisitor<List<KeyPathNode>> visitor = new ConfigurationVisitor<>() {

        /**
         * List with the result.
         */
        private List<KeyPathNode> res = new ArrayList<>(keys.size());

        /**
         * Current index.
         */
        private int idx = 1;

        /**
         * {@inheritDoc}
         */
        @Nullable
        @Override
        public List<KeyPathNode> visitLeafNode(String key, Serializable val) {
            res.add(new KeyPathNode(key));
            return res;
        }

        /**
         * {@inheritDoc}
         */
        @Nullable
        @Override
        public List<KeyPathNode> visitInnerNode(String key, InnerNode node) {
            res.add(new KeyPathNode(key));
            if (keys.size() == idx) {
                return res;
            }
            node.traverseChild(keys.get(idx++), this, true);
            return res;
        }

        /**
         * {@inheritDoc}
         */
        @Nullable
        @Override
        public List<KeyPathNode> visitNamedListNode(String key, NamedListNode node) {
            res.add(new KeyPathNode(key));
            if (keys.size() == idx) {
                return res;
            }
            InnerNode innerNode = node.getInnerNode(keys.get(idx++));
            if (innerNode == null) {
                throw noSuchElementException();
            }
            // This is important, node is added as a resolved named list entry here.
            res.add(new KeyPathNode(innerNode.internalId().toString(), false));
            if (keys.size() == idx) {
                return res;
            }
            innerNode.traverseChild(keys.get(idx++), this, true);
            return res;
        }
    };
    return changer.getRootNode(rootKey).accept(keys.get(0), visitor);
}
Also used : Serializable(java.io.Serializable) NamedListNode(org.apache.ignite.internal.configuration.tree.NamedListNode) ArrayList(java.util.ArrayList) List(java.util.List) ConfigurationVisitor(org.apache.ignite.internal.configuration.tree.ConfigurationVisitor) KeyPathNode(org.apache.ignite.internal.configuration.direct.KeyPathNode) InnerNode(org.apache.ignite.internal.configuration.tree.InnerNode)

Aggregations

KeyPathNode (org.apache.ignite.internal.configuration.direct.KeyPathNode)4 Serializable (java.io.Serializable)3 InnerNode (org.apache.ignite.internal.configuration.tree.InnerNode)3 List (java.util.List)2 NoSuchElementException (java.util.NoSuchElementException)2 ConfigurationVisitor (org.apache.ignite.internal.configuration.tree.ConfigurationVisitor)2 NamedListNode (org.apache.ignite.internal.configuration.tree.NamedListNode)2 BytecodeBlock (com.facebook.presto.bytecode.BytecodeBlock)1 MethodDefinition (com.facebook.presto.bytecode.MethodDefinition)1 ParameterizedType (com.facebook.presto.bytecode.ParameterizedType)1 BytecodeExpressions.constantString (com.facebook.presto.bytecode.expression.BytecodeExpressions.constantString)1 ArrayList (java.util.ArrayList)1 Arrays.asList (java.util.Arrays.asList)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 RandomAccess (java.util.RandomAccess)1 StringJoiner (java.util.StringJoiner)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 Collectors.toMap (java.util.stream.Collectors.toMap)1 ConfigurationWrongPolymorphicTypeIdException (org.apache.ignite.configuration.ConfigurationWrongPolymorphicTypeIdException)1