/* * 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 java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.igfs.IgfsMode; import org.apache.ignite.igfs.IgfsPath; import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashMap; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.T2; import org.apache.ignite.internal.util.typedef.internal.U; import org.jetbrains.annotations.Nullable; /** * */ public class IgfsModeResolver implements Externalizable { /** */ private static final long serialVersionUID = 0L; /** Maximum size of map with cached path modes. */ private static final int MAX_PATH_CACHE = 1000; /** Default mode. */ private IgfsMode dfltMode; /** Modes for particular paths. Ordered from longest to shortest. */ private List<T2<IgfsPath, IgfsMode>> modes; /** Cached modes per path. */ private Map<IgfsPath, IgfsMode> modesCache; /** Set to store parent dual paths that have primary children. */ private Set<IgfsPath> dualParentsWithPrimaryChildren; /** * Empty constructor required by {@link Externalizable}. */ public IgfsModeResolver() { // No-op. } /** * Constructor * * @param dfltMode Default IGFS mode. * @param modes List of configured modes. The order is significant as modes are added in order of occurrence. * @throws IgniteCheckedException On error. */ public IgfsModeResolver(IgfsMode dfltMode, @Nullable ArrayList<T2<IgfsPath, IgfsMode>> modes) throws IgniteCheckedException { assert dfltMode != null; this.dfltMode = dfltMode; dualParentsWithPrimaryChildren = new HashSet<>(); this.modes = IgfsUtils.preparePathModes(dfltMode, modes, dualParentsWithPrimaryChildren); if (modes != null) modesCache = new GridBoundedConcurrentLinkedHashMap<>(MAX_PATH_CACHE); } /** * Resolves IGFS mode for the given path. * * @param path IGFS path. * @return IGFS mode. */ public IgfsMode resolveMode(IgfsPath path) { assert path != null; if (modes == null) return dfltMode; else { IgfsMode mode = modesCache.get(path); if (mode == null) { for (T2<IgfsPath, IgfsMode> entry : modes) { if (F.eq(path, entry.getKey()) || path.isSubDirectoryOf(entry.getKey())) { // As modes ordered from most specific to least specific first mode found is ours. mode = entry.getValue(); break; } } if (mode == null) mode = dfltMode; modesCache.put(path, mode); } return mode; } } /** * Answers if the given path has an immediate child of PRIMARY mode. * * @param path The path to query. * @return If the given path has an immediate child of PRIMARY mode. */ public boolean hasPrimaryChild(IgfsPath path) { return dualParentsWithPrimaryChildren.contains(path); } /** {@inheritDoc} */ @Override public void writeExternal(ObjectOutput out) throws IOException { U.writeEnum(out, dfltMode); if (modes != null) { out.writeBoolean(true); out.writeInt(modes.size()); for (T2<IgfsPath, IgfsMode> pathMode : modes) { assert pathMode.getKey() != null; pathMode.getKey().writeExternal(out); U.writeEnum(out, pathMode.getValue()); } } else out.writeBoolean(false); if (!F.isEmpty(dualParentsWithPrimaryChildren)) { out.writeBoolean(true); out.writeInt(dualParentsWithPrimaryChildren.size()); for (IgfsPath p : dualParentsWithPrimaryChildren) p.writeExternal(out); } else out.writeBoolean(false); } /** {@inheritDoc} */ @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { dfltMode = IgfsMode.fromOrdinal(in.readByte()); if (in.readBoolean()) { int size = in.readInt(); modes = new ArrayList<>(size); for (int i = 0; i < size; i++) { IgfsPath path = IgfsUtils.readPath(in); modes.add(new T2<>(path, IgfsMode.fromOrdinal(in.readByte()))); } modesCache = new GridBoundedConcurrentLinkedHashMap<>(MAX_PATH_CACHE); } dualParentsWithPrimaryChildren = new HashSet<>(); if (in.readBoolean()) { int size = in.readInt(); for (int i = 0; i < size; i++) dualParentsWithPrimaryChildren.add(IgfsUtils.readPath(in)); } } }