blob: 9b30913d4c032bfad0cc4c6da8ea978a4b9d20f4 [file] [log] [blame]
/*
* 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;
}
}