| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.igfs; |
| |
| import org.apache.ignite.igfs.IgfsPath; |
| import org.apache.ignite.lang.IgniteUuid; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.Collection; |
| import java.util.Map; |
| |
| /** |
| * Path IDs abstraction. Contains path and corresponding IDs. |
| */ |
| public class IgfsPathIds { |
| /** Original path. */ |
| private final IgfsPath path; |
| |
| /** Path parts. */ |
| private final String[] parts; |
| |
| /** IDs. */ |
| private final IgniteUuid[] ids; |
| |
| /** Surrogate IDs for paths which doesn't exist yet. Initialized on demand. */ |
| private IgniteUuid[] surrogateIds; |
| |
| /** Index of last existing ID. */ |
| private final int lastExistingIdx; |
| |
| /** |
| * Constructor. |
| * |
| * @param path Path. |
| * @param parts Path parts. |
| * @param ids IDs. |
| */ |
| public IgfsPathIds(IgfsPath path, String[] parts, IgniteUuid[] ids) { |
| assert path != null; |
| assert parts.length == ids.length; |
| |
| this.path = path; |
| this.parts = parts; |
| this.ids = ids; |
| |
| int lastExistingIdx0 = -1; |
| |
| for (int i = parts.length - 1; i >= 0; i--) { |
| if (ids[i] != null) { |
| lastExistingIdx0 = i; |
| |
| break; |
| } |
| } |
| |
| assert lastExistingIdx0 >= 0; |
| |
| lastExistingIdx = lastExistingIdx0; |
| } |
| |
| /** |
| * Get parent entity. |
| * |
| * @return Parent entity. |
| */ |
| public IgfsPathIds parent() { |
| assert ids.length > 1; |
| |
| String[] parentParts = new String[parts.length - 1]; |
| IgniteUuid[] parentIds = new IgniteUuid[ids.length - 1]; |
| |
| System.arraycopy(parts, 0, parentParts, 0, parentParts.length); |
| System.arraycopy(ids, 0, parentIds, 0, parentIds.length); |
| |
| return new IgfsPathIds(path.parent(), parentParts, parentIds); |
| } |
| |
| /** |
| * Get number of elements. |
| * |
| * @return ID count. |
| */ |
| public int count() { |
| return ids.length; |
| } |
| |
| /** |
| * Get original path. |
| * |
| * @return Path. |
| */ |
| public IgfsPath path() { |
| return path; |
| } |
| |
| /** |
| * Get path part at the given index. |
| * |
| * @param idx Index. |
| * @return Path part. |
| */ |
| public String part(int idx) { |
| assert idx < parts.length; |
| |
| return parts[idx]; |
| } |
| |
| /** |
| * Get last part of original path. |
| * |
| * @return Last part. |
| */ |
| public String lastPart() { |
| return parts[parts.length - 1]; |
| } |
| |
| /** |
| * Get last ID. |
| * |
| * @return Last ID. |
| */ |
| public IgniteUuid lastId() { |
| return ids[ids.length - 1]; |
| } |
| |
| /** |
| * Get last parent ID. |
| * |
| * @return Last parent ID. |
| */ |
| @Nullable public IgniteUuid lastParentId() { |
| return ids[ids.length - 2]; |
| } |
| |
| /** |
| * Whether provided index denotes last entry in the path. |
| * |
| * @param idx Index. |
| * @return {@code True} if last. |
| */ |
| public boolean isLastIndex(int idx) { |
| return idx == parts.length - 1; |
| } |
| |
| /** |
| * Get path of the last existing element. |
| * |
| * @return Path of the last existing element. |
| */ |
| public IgfsPath lastExistingPath() { |
| IgfsPath path = IgfsPath.ROOT; |
| |
| for (int i = 1; i <= lastExistingIdx; i++) |
| path = new IgfsPath(path, parts[i]); |
| |
| return path; |
| } |
| |
| /** |
| * Whether all parts exists. |
| * |
| * @return {@code True} if all parts were found. |
| */ |
| public boolean allExists() { |
| return parts.length == lastExistingIdx + 1; |
| } |
| |
| /** |
| * Whether last entry exists. |
| * |
| * @return {@code True} if exists. |
| */ |
| public boolean lastExists() { |
| return lastExistingIdx == ids.length - 1; |
| } |
| |
| |
| /** |
| * Whether parent of the last entry exists. |
| * |
| * @return {@code True} if exists. |
| */ |
| public boolean lastParentExists() { |
| return ids.length > 1 && lastExistingIdx == ids.length - 2; |
| } |
| |
| /** |
| * Get ID of the last existing entry. |
| * |
| * @return ID of the last existing entry. |
| */ |
| public IgniteUuid lastExistingId() { |
| return ids[lastExistingIdx]; |
| } |
| |
| /** |
| * Get index of the last existing entry. |
| * |
| * @return Index of the last existing entry. |
| */ |
| public int lastExistingIndex() { |
| return lastExistingIdx; |
| } |
| |
| /** |
| * Add existing IDs to provided collection. |
| * |
| * @param col Collection. |
| * @param relaxed Relaxed mode flag. |
| */ |
| @SuppressWarnings("ManualArrayToCollectionCopy") |
| public void addExistingIds(Collection<IgniteUuid> col, boolean relaxed) { |
| if (relaxed) { |
| col.add(ids[lastExistingIdx]); |
| |
| if (lastExistingIdx == ids.length - 1 && lastExistingIdx > 0) |
| col.add(ids[lastExistingIdx - 1]); |
| } |
| else { |
| for (int i = 0; i <= lastExistingIdx; i++) |
| col.add(ids[i]); |
| } |
| } |
| |
| /** |
| * Add surrogate IDs to provided collection potentially creating them on demand. |
| * |
| * @param col Collection. |
| */ |
| @SuppressWarnings("ManualArrayToCollectionCopy") |
| public void addSurrogateIds(Collection<IgniteUuid> col) { |
| if (surrogateIds == null) { |
| surrogateIds = new IgniteUuid[ids.length]; |
| |
| for (int i = lastExistingIdx + 1; i < surrogateIds.length; i++) |
| surrogateIds[i] = IgniteUuid.randomUuid(); |
| } |
| |
| for (int i = lastExistingIdx + 1; i < surrogateIds.length; i++) |
| col.add(surrogateIds[i]); |
| } |
| |
| /** |
| * Get ID at the give index. |
| * |
| * @param idx Index. |
| * @return ID. |
| */ |
| public IgniteUuid id(int idx) { |
| return idx <= lastExistingIdx ? ids[idx] : surrogateId(idx); |
| } |
| |
| /** |
| * Get surrogate ID at the given index. |
| * |
| * @param idx Index. |
| * @return Surrogate ID. |
| */ |
| public IgniteUuid surrogateId(int idx) { |
| assert surrogateIds != null; |
| |
| assert idx > lastExistingIdx; |
| assert idx < surrogateIds.length; |
| |
| return surrogateIds[idx]; |
| } |
| |
| /** |
| * Verify that observed paths are found in provided infos in the right order. |
| * |
| * @param infos Info. |
| * @param relaxed Whether to perform check in relaxed mode. |
| * @return {@code True} if full integrity is preserved. |
| */ |
| public boolean verifyIntegrity(Map<IgniteUuid, IgfsEntryInfo> infos, boolean relaxed) { |
| if (relaxed) { |
| // Relaxed mode ensures that the last element is there. If this element is the last in the path, then |
| // existence of it's parent and link between them are checked as well. |
| IgfsEntryInfo info = infos.get(ids[lastExistingIdx]); |
| |
| if (info == null) |
| return false; |
| |
| if (lastExistingIdx == ids.length - 1 && lastExistingIdx > 0) { |
| IgfsEntryInfo parentInfo = infos.get(ids[lastExistingIdx - 1]); |
| |
| if (parentInfo == null || !parentInfo.hasChild(parts[lastExistingIdx], ids[lastExistingIdx])) |
| return false; |
| } |
| } |
| else { |
| // Strict mode ensures that all participants are in place and are still linked. |
| for (int i = 0; i <= lastExistingIdx; i++) { |
| IgfsEntryInfo info = infos.get(ids[i]); |
| |
| // Check if required ID is there. |
| if (info == null) |
| return false; |
| |
| // For non-leaf entry we check if child exists. |
| if (i < lastExistingIdx) { |
| if (!info.hasChild(parts[i + 1], ids[i + 1])) |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| } |