Example usage for com.google.common.collect BiMap containsKey

List of usage examples for com.google.common.collect BiMap containsKey

Introduction

In this page you can find the example usage for com.google.common.collect BiMap containsKey.

Prototype

boolean containsKey(Object key);

Source Link

Document

Returns true if this map contains a mapping for the specified key.

Usage

From source file:org.apache.druid.indexing.common.task.CompactionTask.java

private static DimensionsSpec createDimensionsSpec(List<Pair<QueryableIndex, DataSegment>> queryableIndices) {
    final BiMap<String, Integer> uniqueDims = HashBiMap.create();
    final Map<String, DimensionSchema> dimensionSchemaMap = new HashMap<>();

    // Here, we try to retain the order of dimensions as they were specified since the order of dimensions may be
    // optimized for performance.
    // Dimensions are extracted from the recent segments to olders because recent segments are likely to be queried more
    // frequently, and thus the performance should be optimized for recent ones rather than old ones.

    // timelineSegments are sorted in order of interval, but we do a sanity check here.
    final Comparator<Interval> intervalComparator = Comparators.intervalsByStartThenEnd();
    for (int i = 0; i < queryableIndices.size() - 1; i++) {
        final Interval shouldBeSmaller = queryableIndices.get(i).lhs.getDataInterval();
        final Interval shouldBeLarger = queryableIndices.get(i + 1).lhs.getDataInterval();
        Preconditions.checkState(intervalComparator.compare(shouldBeSmaller, shouldBeLarger) <= 0,
                "QueryableIndexes are not sorted! Interval[%s] of segment[%s] is laster than interval[%s] of segment[%s]",
                shouldBeSmaller, queryableIndices.get(i).rhs.getIdentifier(), shouldBeLarger,
                queryableIndices.get(i + 1).rhs.getIdentifier());
    }/*from   w w  w  . java  2 s. co m*/

    int index = 0;
    for (Pair<QueryableIndex, DataSegment> pair : Lists.reverse(queryableIndices)) {
        final QueryableIndex queryableIndex = pair.lhs;
        final Map<String, DimensionHandler> dimensionHandlerMap = queryableIndex.getDimensionHandlers();

        for (String dimension : queryableIndex.getAvailableDimensions()) {
            final ColumnHolder columnHolder = Preconditions.checkNotNull(
                    queryableIndex.getColumnHolder(dimension), "Cannot find column for dimension[%s]",
                    dimension);

            if (!uniqueDims.containsKey(dimension)) {
                final DimensionHandler dimensionHandler = Preconditions.checkNotNull(
                        dimensionHandlerMap.get(dimension), "Cannot find dimensionHandler for dimension[%s]",
                        dimension);

                uniqueDims.put(dimension, index++);
                dimensionSchemaMap.put(dimension,
                        createDimensionSchema(columnHolder.getCapabilities().getType(), dimension,
                                dimensionHandler.getMultivalueHandling(),
                                columnHolder.getCapabilities().hasBitmapIndexes()));
            }
        }
    }

    final BiMap<Integer, String> orderedDims = uniqueDims.inverse();
    final List<DimensionSchema> dimensionSchemas = IntStream.range(0, orderedDims.size()).mapToObj(i -> {
        final String dimName = orderedDims.get(i);
        return Preconditions.checkNotNull(dimensionSchemaMap.get(dimName),
                "Cannot find dimension[%s] from dimensionSchemaMap", dimName);
    }).collect(Collectors.toList());

    return new DimensionsSpec(dimensionSchemas, null, null);
}

From source file:cpw.mods.fml.common.Loader.java

/**
 * Sort the mods into a sorted list, using dependency information from the
 * containers. The sorting is performed using a {@link TopologicalSort}
 * based on the pre- and post- dependency information provided by the mods.
 *///from www .  j  a  v a 2  s. c o m
private void sortModList() {
    FMLLog.finer("Verifying mod requirements are satisfied");
    try {
        BiMap<String, ArtifactVersion> modVersions = HashBiMap.create();
        for (ModContainer mod : getActiveModList()) {
            modVersions.put(mod.getModId(), mod.getProcessedVersion());
        }

        ArrayListMultimap<String, String> reqList = ArrayListMultimap.create();
        for (ModContainer mod : getActiveModList()) {
            if (!mod.acceptableMinecraftVersionRange().containsVersion(minecraft.getProcessedVersion())) {
                FMLLog.severe(
                        "The mod %s does not wish to run in Minecraft version %s. You will have to remove it to play.",
                        mod.getModId(), getMCVersionString());
                throw new WrongMinecraftVersionException(mod);
            }
            Map<String, ArtifactVersion> names = Maps.uniqueIndex(mod.getRequirements(),
                    new ArtifactVersionNameFunction());
            Set<ArtifactVersion> versionMissingMods = Sets.newHashSet();

            Set<String> missingMods = Sets.difference(names.keySet(), modVersions.keySet());
            if (!missingMods.isEmpty()) {
                FMLLog.severe("The mod %s (%s) requires mods %s to be available", mod.getModId(), mod.getName(),
                        missingMods);
                for (String modid : missingMods) {
                    versionMissingMods.add(names.get(modid));
                }
                throw new MissingModsException(versionMissingMods);
            }
            reqList.putAll(mod.getModId(), names.keySet());
            ImmutableList<ArtifactVersion> allDeps = ImmutableList.<ArtifactVersion>builder()
                    .addAll(mod.getDependants()).addAll(mod.getDependencies()).build();
            for (ArtifactVersion v : allDeps) {
                if (modVersions.containsKey(v.getLabel())) {
                    if (!v.containsVersion(modVersions.get(v.getLabel()))) {
                        versionMissingMods.add(v);
                    }
                }
            }
            if (!versionMissingMods.isEmpty()) {
                FMLLog.severe("The mod %s (%s) requires mod versions %s to be available", mod.getModId(),
                        mod.getName(), versionMissingMods);
                throw new MissingModsException(versionMissingMods);
            }
        }

        FMLLog.finer("All mod requirements are satisfied");

        reverseDependencies = Multimaps.invertFrom(reqList, ArrayListMultimap.<String, String>create());
        ModSorter sorter = new ModSorter(getActiveModList(), namedMods);

        try {
            FMLLog.finer("Sorting mods into an ordered list");
            List<ModContainer> sortedMods = sorter.sort();
            // Reset active list to the sorted list
            modController.getActiveModList().clear();
            modController.getActiveModList().addAll(sortedMods);
            // And inject the sorted list into the overall list
            mods.removeAll(sortedMods);
            sortedMods.addAll(mods);
            mods = sortedMods;
            FMLLog.finer("Mod sorting completed successfully");
        } catch (ModSortingException sortException) {
            FMLLog.severe(
                    "A dependency cycle was detected in the input mod set so an ordering cannot be determined");
            SortingExceptionData<ModContainer> exceptionData = sortException.getExceptionData();
            FMLLog.severe("The first mod in the cycle is %s", exceptionData.getFirstBadNode());
            FMLLog.severe("The mod cycle involves");
            for (ModContainer mc : exceptionData.getVisitedNodes()) {
                FMLLog.severe("%s : before: %s, after: %s", mc.toString(), mc.getDependants(),
                        mc.getDependencies());
            }
            FMLLog.log(Level.ERROR, sortException, "The full error");
            throw sortException;
        }
    } finally {
        FMLLog.fine("Mod sorting data");
        int unprintedMods = mods.size();
        for (ModContainer mod : getActiveModList()) {
            if (!mod.isImmutable()) {
                FMLLog.fine("\t%s(%s:%s): %s (%s)", mod.getModId(), mod.getName(), mod.getVersion(),
                        mod.getSource().getName(), mod.getSortingRules());
                unprintedMods--;
            }
        }
        if (unprintedMods == mods.size()) {
            FMLLog.fine("No user mods found to sort");
        }
    }

}

From source file:net.minecraftforge.fml.common.Loader.java

/**
 * Sort the mods into a sorted list, using dependency information from the
 * containers. The sorting is performed using a {@link TopologicalSort}
 * based on the pre- and post- dependency information provided by the mods.
 *//*  w w w. ja v a2 s .com*/
private void sortModList() {
    FMLLog.finer("Verifying mod requirements are satisfied");
    try {
        BiMap<String, ArtifactVersion> modVersions = HashBiMap.create();
        for (ModContainer mod : Iterables.concat(getActiveModList(), ModAPIManager.INSTANCE.getAPIList())) {
            modVersions.put(mod.getModId(), mod.getProcessedVersion());
        }

        ArrayListMultimap<String, String> reqList = ArrayListMultimap.create();
        for (ModContainer mod : getActiveModList()) {
            if (!mod.acceptableMinecraftVersionRange().containsVersion(minecraft.getProcessedVersion())) {
                FMLLog.severe(
                        "The mod %s does not wish to run in Minecraft version %s. You will have to remove it to play.",
                        mod.getModId(), getMCVersionString());
                throw new WrongMinecraftVersionException(mod);
            }
            Map<String, ArtifactVersion> names = Maps.uniqueIndex(mod.getRequirements(),
                    new ArtifactVersionNameFunction());
            Set<ArtifactVersion> versionMissingMods = Sets.newHashSet();

            Set<String> missingMods = Sets.difference(names.keySet(), modVersions.keySet());
            if (!missingMods.isEmpty()) {
                FMLLog.severe("The mod %s (%s) requires mods %s to be available", mod.getModId(), mod.getName(),
                        missingMods);
                for (String modid : missingMods) {
                    versionMissingMods.add(names.get(modid));
                }
                throw new MissingModsException(versionMissingMods, mod.getModId(), mod.getName());
            }
            reqList.putAll(mod.getModId(), names.keySet());
            ImmutableList<ArtifactVersion> allDeps = ImmutableList.<ArtifactVersion>builder()
                    .addAll(mod.getDependants()).addAll(mod.getDependencies()).build();
            for (ArtifactVersion v : allDeps) {
                if (modVersions.containsKey(v.getLabel())) {
                    if (!v.containsVersion(modVersions.get(v.getLabel()))) {
                        versionMissingMods.add(v);
                    }
                }
            }
            if (!versionMissingMods.isEmpty()) {
                FMLLog.severe("The mod %s (%s) requires mod versions %s to be available", mod.getModId(),
                        mod.getName(), versionMissingMods);
                throw new MissingModsException(versionMissingMods, mod.getModId(), mod.getName());
            }
        }

        FMLLog.finer("All mod requirements are satisfied");

        reverseDependencies = Multimaps.invertFrom(reqList, ArrayListMultimap.<String, String>create());
        ModSorter sorter = new ModSorter(getActiveModList(), namedMods);

        try {
            FMLLog.finer("Sorting mods into an ordered list");
            List<ModContainer> sortedMods = sorter.sort();
            // Reset active list to the sorted list
            modController.getActiveModList().clear();
            modController.getActiveModList().addAll(sortedMods);
            // And inject the sorted list into the overall list
            mods.removeAll(sortedMods);
            sortedMods.addAll(mods);
            mods = sortedMods;
            FMLLog.finer("Mod sorting completed successfully");
        } catch (ModSortingException sortException) {
            FMLLog.severe(
                    "A dependency cycle was detected in the input mod set so an ordering cannot be determined");
            SortingExceptionData<ModContainer> exceptionData = sortException.getExceptionData();
            FMLLog.severe("The first mod in the cycle is %s", exceptionData.getFirstBadNode());
            FMLLog.severe("The mod cycle involves");
            for (ModContainer mc : exceptionData.getVisitedNodes()) {
                FMLLog.severe("%s : before: %s, after: %s", mc.toString(), mc.getDependants(),
                        mc.getDependencies());
            }
            FMLLog.log(Level.ERROR, sortException, "The full error");
            throw sortException;
        }
    } finally {
        FMLLog.fine("Mod sorting data");
        int unprintedMods = mods.size();
        for (ModContainer mod : getActiveModList()) {
            if (!mod.isImmutable()) {
                FMLLog.fine("\t%s(%s:%s): %s (%s)", mod.getModId(), mod.getName(), mod.getVersion(),
                        mod.getSource().getName(), mod.getSortingRules());
                unprintedMods--;
            }
        }
        if (unprintedMods == mods.size()) {
            FMLLog.fine("No user mods found to sort");
        }
    }

}

From source file:com.moz.fiji.schema.layout.FijiTableLayout.java

/**
 * Constructs a FijiTableLayout from an Avro descriptor and an optional reference layout.
 *
 * @param desc Avro layout descriptor (relative to the reference layout).
 * @param reference Optional reference layout, or null.
 * @throws InvalidLayoutException if the descriptor is invalid or inconsistent wrt reference.
 */// w  w w .  j a  va  2  s .  c  om
private FijiTableLayout(TableLayoutDesc desc, FijiTableLayout reference) throws InvalidLayoutException {
    // Deep-copy the descriptor to prevent mutating a parameter:
    mDesc = TableLayoutDesc.newBuilder(Preconditions.checkNotNull(desc)).build();

    // Ensure the array of locality groups is mutable:
    mDesc.setLocalityGroups(Lists.newArrayList(mDesc.getLocalityGroups()));

    // Check that the version specified in the layout matches the features used.
    // Any compatibility checks belong in this section.
    mLayoutVersion = computeLayoutVersion(mDesc.getVersion());

    if (!Objects.equal(LAYOUT_PROTOCOL_NAME, mLayoutVersion.getProtocolName())) {
        final String exceptionMessage;
        if (Objects.equal(Versions.LAYOUT_FIJI_1_0_0_DEPRECATED.getProtocolName(),
                mLayoutVersion.getProtocolName())) {
            // Warn the user if they tried a version number like 'fiji-0.9' or 'fiji-1.1'.
            exceptionMessage = String.format(
                    "Deprecated layout version protocol '%s' only valid for version '%s',"
                            + " but received version '%s'. You should specify a layout version protocol"
                            + " as '%s-x.y', not '%s-x.y'.",
                    Versions.LAYOUT_FIJI_1_0_0_DEPRECATED.getProtocolName(),
                    Versions.LAYOUT_FIJI_1_0_0_DEPRECATED, mLayoutVersion, LAYOUT_PROTOCOL_NAME,
                    Versions.LAYOUT_FIJI_1_0_0_DEPRECATED.getProtocolName());
        } else {
            exceptionMessage = String.format("Invalid version protocol: '%s'. Expected '%s'.",
                    mLayoutVersion.getProtocolName(), LAYOUT_PROTOCOL_NAME);
        }
        throw new InvalidLayoutException(exceptionMessage);
    }

    if (Versions.MAX_LAYOUT_VERSION.compareTo(mLayoutVersion) < 0) {
        throw new InvalidLayoutException("The maximum layout version we support is "
                + Versions.MAX_LAYOUT_VERSION + "; this layout requires " + mLayoutVersion);
    } else if (Versions.MIN_LAYOUT_VERSION.compareTo(mLayoutVersion) > 0) {
        throw new InvalidLayoutException("The minimum layout version we support is "
                + Versions.MIN_LAYOUT_VERSION + "; this layout requires " + mLayoutVersion);
    }

    // max_filesize and memstore_flushsize were introduced in version 1.2.
    if (Versions.BLOCK_SIZE_LAYOUT_VERSION.compareTo(mLayoutVersion) > 0) {
        if (mDesc.getMaxFilesize() != null) {
            // Cannot use max_filesize if this is the case.
            throw new InvalidLayoutException("Support for specifying max_filesize begins with layout version "
                    + Versions.BLOCK_SIZE_LAYOUT_VERSION.toString());
        }

        if (mDesc.getMemstoreFlushsize() != null) {
            // Cannot use memstore_flushsize if this is the case.
            throw new InvalidLayoutException(
                    "Support for specifying memstore_flushsize begins with layout version "
                            + Versions.BLOCK_SIZE_LAYOUT_VERSION);
        }
    } else {
        if (mDesc.getMaxFilesize() != null && mDesc.getMaxFilesize() <= 0) {
            throw new InvalidLayoutException("max_filesize must be greater than 0");
        }

        if (mDesc.getMemstoreFlushsize() != null && mDesc.getMemstoreFlushsize() <= 0) {
            throw new InvalidLayoutException("memstore_flushsize must be greater than 0");
        }
    }

    // Ability to configure column name translation was introduced in version 1.5
    if (Versions.CONFIGURE_COLUMN_NAME_TRANSLATION_VERSION.compareTo(mLayoutVersion) > 0) {
        if (mDesc.getColumnNameTranslator() != ColumnNameTranslator.SHORT) {
            throw new InvalidLayoutException(
                    "Support for specifiying non-short column name translators begins with layout version "
                            + Versions.CONFIGURE_COLUMN_NAME_TRANSLATION_VERSION);
        }
    }

    // Composite keys and RowKeyFormat2 was introduced in version 1.1.
    if (Versions.RKF2_LAYOUT_VERSION.compareTo(mLayoutVersion) > 0
            && mDesc.getKeysFormat() instanceof RowKeyFormat2) {
        // Cannot use RowKeyFormat2 if this is the case.
        throw new InvalidLayoutException(
                "Support for specifying keys_format as a RowKeyFormat2 begins with layout version "
                        + Versions.RKF2_LAYOUT_VERSION);
    }

    if (!isValidName(getName())) {
        throw new InvalidLayoutException(String.format("Invalid table name: '%s'.", getName()));
    }

    if (reference != null) {
        if (!getName().equals(reference.getName())) {
            throw new InvalidLayoutException(String.format(
                    "Invalid layout update: layout name '%s' does not match reference layout name '%s'.",
                    getName(), reference.getName()));
        }

        if (!mDesc.getKeysFormat().equals(reference.getDesc().getKeysFormat())) {
            throw new InvalidLayoutException(String.format(
                    "Invalid layout update from reference row keys format '%s' to row keys format '%s'.",
                    reference.getDesc().getKeysFormat(), mDesc.getKeysFormat()));
        }
    }

    // Layout ID:
    if (mDesc.getLayoutId() == null) {
        try {
            final long refLayoutId = (reference == null) ? 0
                    : Long.parseLong(reference.getDesc().getLayoutId());
            final long layoutId = refLayoutId + 1;
            mDesc.setLayoutId(Long.toString(layoutId));
        } catch (NumberFormatException nfe) {
            throw new InvalidLayoutException(
                    String.format("Reference layout for table '%s' has an invalid layout ID: '%s'", getName(),
                            reference.getDesc().getLayoutId()));
        }
    }

    if (mDesc.getKeysFormat() instanceof RowKeyFormat) {
        isValidRowKeyFormat1((RowKeyFormat) mDesc.getKeysFormat());
    } else if (mDesc.getKeysFormat() instanceof RowKeyFormat2) {
        // Check validity of row key format.
        isValidRowKeyFormat2((RowKeyFormat2) mDesc.getKeysFormat());
    }

    // Build localities:

    /**
     * Reference map from locality group name to locality group ID.
     * Entries are removed as we process locality group descriptors in the new layout.
     * At the end of the process, this map must be empty.
     */
    final BiMap<String, ColumnId> refLGIdMap = (reference == null) ? HashBiMap.<String, ColumnId>create()
            : HashBiMap.create(reference.mLocalityGroupIdNameMap.inverse());

    /** Map of locality groups in the new layout. */
    final List<LocalityGroupLayout> localityGroups = Lists.newArrayList();
    final Map<String, LocalityGroupLayout> lgMap = Maps.newHashMap();
    final BiMap<ColumnId, String> idMap = HashBiMap.create();

    /** Locality group with no ID assigned yet. */
    final List<LocalityGroupLayout> unassigned = Lists.newArrayList();

    /** All the families in the table. */
    final List<FamilyLayout> families = Lists.newArrayList();

    /** Map from family name or alias to family layout. */
    final Map<String, FamilyLayout> familyMap = Maps.newHashMap();

    /** All primary column names (including map-type families). */
    final Set<FijiColumnName> columnNames = Sets.newTreeSet();

    final Map<FijiColumnName, ColumnLayout> columnMap = Maps.newHashMap();

    final Iterator<LocalityGroupDesc> itLGDesc = mDesc.getLocalityGroups().iterator();
    while (itLGDesc.hasNext()) {
        final LocalityGroupDesc lgDesc = itLGDesc.next();
        final boolean isRename = (lgDesc.getRenamedFrom() != null);
        final String refLGName = isRename ? lgDesc.getRenamedFrom() : lgDesc.getName();
        lgDesc.setRenamedFrom(null);
        if (isRename && (reference == null)) {
            throw new InvalidLayoutException(String
                    .format("Invalid rename: no reference table layout for locality group '%s'.", refLGName));
        }
        final LocalityGroupLayout refLGLayout = (reference != null) ? reference.mLocalityGroupMap.get(refLGName)
                : null;
        if (isRename && (refLGLayout == null)) {
            throw new InvalidLayoutException(
                    String.format("Invalid rename: cannot find reference locality group '%s'.", refLGName));
        }

        final ColumnId refLGId = refLGIdMap.remove(refLGName);

        if (lgDesc.getDelete()) {
            // This locality group is deleted:
            if (refLGId == null) {
                throw new InvalidLayoutException(String.format(
                        "Attempting to delete locality group '%s' unknown in reference layout.", refLGName));
            }
            itLGDesc.remove();
            continue;
        }

        // BloomType, block_size were introduced in version 1.2.
        if (Versions.BLOCK_SIZE_LAYOUT_VERSION.compareTo(mLayoutVersion) > 0) {
            if (lgDesc.getBlockSize() != null) {
                // Cannot use max_filesize if this is the case.
                throw new InvalidLayoutException("Support for specifying block_size begins with layout version "
                        + Versions.BLOCK_SIZE_LAYOUT_VERSION);
            }
            if (lgDesc.getBloomType() != null) {
                // Cannot use bloom_type if this is the case.
                throw new InvalidLayoutException("Support for specifying bloom_type begins with layout version "
                        + Versions.BLOCK_SIZE_LAYOUT_VERSION);
            }
        } else {
            if (lgDesc.getBlockSize() != null && lgDesc.getBlockSize() <= 0) {
                throw new InvalidLayoutException("block_size must be greater than 0");
            }
        }

        final LocalityGroupLayout lgLayout = new LocalityGroupLayout(lgDesc, refLGLayout);
        localityGroups.add(lgLayout);
        for (String lgName : lgLayout.getNames()) {
            Preconditions.checkState(lgMap.put(lgName, lgLayout) == null,
                    "Duplicate locality group name: " + lgName);
        }

        if (lgLayout.getId() != null) {
            final String previous = idMap.put(lgLayout.getId(), lgLayout.getName());
            Preconditions.checkState(previous == null,
                    String.format("Duplicate locality group ID '%s' associated to '%s' and '%s'.",
                            lgLayout.getId(), lgLayout.getName(), previous));
        } else {
            unassigned.add(lgLayout);
        }

        families.addAll(lgLayout.getFamilies());
        for (FamilyLayout familyLayout : lgLayout.getFamilies()) {
            for (String familyName : familyLayout.getNames()) {
                if (null != familyMap.put(familyName, familyLayout)) {
                    throw new InvalidLayoutException(
                            String.format("Layout for table '%s' contains duplicate family name '%s'.",
                                    getName(), familyName));
                }
            }

            if (familyLayout.isMapType()) {
                Preconditions.checkState(columnNames.add(FijiColumnName.create(familyLayout.getName(), null)));
            }

            for (ColumnLayout columnLayout : familyLayout.getColumns()) {
                for (String columnName : columnLayout.getNames()) {
                    final FijiColumnName column = FijiColumnName.create(familyLayout.getName(), columnName);
                    if (null != columnMap.put(column, columnLayout)) {
                        throw new InvalidLayoutException(String.format(
                                "Layout for table '%s' contains duplicate column '%s'.", getName(), column));
                    }
                }
                Preconditions.checkState(
                        columnNames.add(FijiColumnName.create(familyLayout.getName(), columnLayout.getName())));
            }
        }
    }

    if (!refLGIdMap.isEmpty()) {
        throw new InvalidLayoutException(String.format("Missing descriptor(s) for locality group(s): %s.",
                Joiner.on(",").join(refLGIdMap.keySet())));
    }

    mLocalityGroups = ImmutableList.copyOf(localityGroups);
    mLocalityGroupMap = ImmutableMap.copyOf(lgMap);

    mFamilies = ImmutableList.copyOf(families);
    mFamilyMap = ImmutableMap.copyOf(familyMap);

    mColumnNames = ImmutableSet.copyOf(columnNames);

    // Assign IDs to locality groups:
    int nextColumnId = 1;
    for (LocalityGroupLayout localityGroup : unassigned) {
        Preconditions.checkState(localityGroup.getId() == null);
        while (true) {
            final ColumnId columnId = new ColumnId(nextColumnId);
            nextColumnId += 1;
            if (!idMap.containsKey(columnId)) {
                localityGroup.setId(columnId);
                idMap.put(columnId, localityGroup.getName());
                break;
            }
        }
    }

    mLocalityGroupIdNameMap = ImmutableBiMap.copyOf(idMap);
}

From source file:org.kiji.schema.layout.KijiTableLayout.java

/**
 * Constructs a KijiTableLayout from an Avro descriptor and an optional reference layout.
 *
 * @param desc Avro layout descriptor (relative to the reference layout).
 * @param reference Optional reference layout, or null.
 * @throws InvalidLayoutException if the descriptor is invalid or inconsistent wrt reference.
 *//*from w w  w  .j  av a2s .  c o  m*/
private KijiTableLayout(TableLayoutDesc desc, KijiTableLayout reference) throws InvalidLayoutException {
    // Deep-copy the descriptor to prevent mutating a parameter:
    mDesc = TableLayoutDesc.newBuilder(Preconditions.checkNotNull(desc)).build();

    // Ensure the array of locality groups is mutable:
    mDesc.setLocalityGroups(Lists.newArrayList(mDesc.getLocalityGroups()));

    // Check that the version specified in the layout matches the features used.
    // Any compatibility checks belong in this section.
    mLayoutVersion = computeLayoutVersion(mDesc.getVersion());

    if (!Objects.equal(LAYOUT_PROTOCOL_NAME, mLayoutVersion.getProtocolName())) {
        final String exceptionMessage;
        if (Objects.equal(Versions.LAYOUT_KIJI_1_0_0_DEPRECATED.getProtocolName(),
                mLayoutVersion.getProtocolName())) {
            // Warn the user if they tried a version number like 'kiji-0.9' or 'kiji-1.1'.
            exceptionMessage = String.format(
                    "Deprecated layout version protocol '%s' only valid for version '%s',"
                            + " but received version '%s'. You should specify a layout version protocol"
                            + " as '%s-x.y', not '%s-x.y'.",
                    Versions.LAYOUT_KIJI_1_0_0_DEPRECATED.getProtocolName(),
                    Versions.LAYOUT_KIJI_1_0_0_DEPRECATED, mLayoutVersion, LAYOUT_PROTOCOL_NAME,
                    Versions.LAYOUT_KIJI_1_0_0_DEPRECATED.getProtocolName());
        } else {
            exceptionMessage = String.format("Invalid version protocol: '%s'. Expected '%s'.",
                    mLayoutVersion.getProtocolName(), LAYOUT_PROTOCOL_NAME);
        }
        throw new InvalidLayoutException(exceptionMessage);
    }

    if (Versions.MAX_LAYOUT_VERSION.compareTo(mLayoutVersion) < 0) {
        throw new InvalidLayoutException("The maximum layout version we support is "
                + Versions.MAX_LAYOUT_VERSION + "; this layout requires " + mLayoutVersion);
    } else if (Versions.MIN_LAYOUT_VERSION.compareTo(mLayoutVersion) > 0) {
        throw new InvalidLayoutException("The minimum layout version we support is "
                + Versions.MIN_LAYOUT_VERSION + "; this layout requires " + mLayoutVersion);
    }

    // max_filesize and memstore_flushsize were introduced in version 1.2.
    if (Versions.BLOCK_SIZE_LAYOUT_VERSION.compareTo(mLayoutVersion) > 0) {
        if (mDesc.getMaxFilesize() != null) {
            // Cannot use max_filesize if this is the case.
            throw new InvalidLayoutException("Support for specifying max_filesize begins with layout version "
                    + Versions.BLOCK_SIZE_LAYOUT_VERSION.toString());
        }

        if (mDesc.getMemstoreFlushsize() != null) {
            // Cannot use memstore_flushsize if this is the case.
            throw new InvalidLayoutException(
                    "Support for specifying memstore_flushsize begins with layout version "
                            + Versions.BLOCK_SIZE_LAYOUT_VERSION);
        }
    } else {
        if (mDesc.getMaxFilesize() != null && mDesc.getMaxFilesize() <= 0) {
            throw new InvalidLayoutException("max_filesize must be greater than 0");
        }

        if (mDesc.getMemstoreFlushsize() != null && mDesc.getMemstoreFlushsize() <= 0) {
            throw new InvalidLayoutException("memstore_flushsize must be greater than 0");
        }
    }

    // Ability to configure column name translation was introduced in version 1.5
    if (Versions.CONFIGURE_COLUMN_NAME_TRANSLATION_VERSION.compareTo(mLayoutVersion) > 0) {
        if (mDesc.getColumnNameTranslator() != ColumnNameTranslator.SHORT) {
            throw new InvalidLayoutException(
                    "Support for specifiying non-short column name translators begins with layout version "
                            + Versions.CONFIGURE_COLUMN_NAME_TRANSLATION_VERSION);
        }
    }

    // Composite keys and RowKeyFormat2 was introduced in version 1.1.
    if (Versions.RKF2_LAYOUT_VERSION.compareTo(mLayoutVersion) > 0
            && mDesc.getKeysFormat() instanceof RowKeyFormat2) {
        // Cannot use RowKeyFormat2 if this is the case.
        throw new InvalidLayoutException(
                "Support for specifying keys_format as a RowKeyFormat2 begins with layout version "
                        + Versions.RKF2_LAYOUT_VERSION);
    }

    if (!isValidName(getName())) {
        throw new InvalidLayoutException(String.format("Invalid table name: '%s'.", getName()));
    }

    if (reference != null) {
        if (!getName().equals(reference.getName())) {
            throw new InvalidLayoutException(String.format(
                    "Invalid layout update: layout name '%s' does not match reference layout name '%s'.",
                    getName(), reference.getName()));
        }

        if (!mDesc.getKeysFormat().equals(reference.getDesc().getKeysFormat())) {
            throw new InvalidLayoutException(String.format(
                    "Invalid layout update from reference row keys format '%s' to row keys format '%s'.",
                    reference.getDesc().getKeysFormat(), mDesc.getKeysFormat()));
        }
    }

    // Layout ID:
    if (mDesc.getLayoutId() == null) {
        try {
            final long refLayoutId = (reference == null) ? 0
                    : Long.parseLong(reference.getDesc().getLayoutId());
            final long layoutId = refLayoutId + 1;
            mDesc.setLayoutId(Long.toString(layoutId));
        } catch (NumberFormatException nfe) {
            throw new InvalidLayoutException(
                    String.format("Reference layout for table '%s' has an invalid layout ID: '%s'", getName(),
                            reference.getDesc().getLayoutId()));
        }
    }

    if (mDesc.getKeysFormat() instanceof RowKeyFormat) {
        isValidRowKeyFormat1((RowKeyFormat) mDesc.getKeysFormat());
    } else if (mDesc.getKeysFormat() instanceof RowKeyFormat2) {
        // Check validity of row key format.
        isValidRowKeyFormat2((RowKeyFormat2) mDesc.getKeysFormat());
    }

    // Build localities:

    /**
     * Reference map from locality group name to locality group ID.
     * Entries are removed as we process locality group descriptors in the new layout.
     * At the end of the process, this map must be empty.
     */
    final BiMap<String, ColumnId> refLGIdMap = (reference == null) ? HashBiMap.<String, ColumnId>create()
            : HashBiMap.create(reference.mLocalityGroupIdNameMap.inverse());

    /** Map of locality groups in the new layout. */
    final List<LocalityGroupLayout> localityGroups = Lists.newArrayList();
    final Map<String, LocalityGroupLayout> lgMap = Maps.newHashMap();
    final BiMap<ColumnId, String> idMap = HashBiMap.create();

    /** Locality group with no ID assigned yet. */
    final List<LocalityGroupLayout> unassigned = Lists.newArrayList();

    /** All the families in the table. */
    final List<FamilyLayout> families = Lists.newArrayList();

    /** Map from family name or alias to family layout. */
    final Map<String, FamilyLayout> familyMap = Maps.newHashMap();

    /** All primary column names (including map-type families). */
    final Set<KijiColumnName> columnNames = Sets.newTreeSet();

    final Map<KijiColumnName, ColumnLayout> columnMap = Maps.newHashMap();

    final Iterator<LocalityGroupDesc> itLGDesc = mDesc.getLocalityGroups().iterator();
    while (itLGDesc.hasNext()) {
        final LocalityGroupDesc lgDesc = itLGDesc.next();
        final boolean isRename = (lgDesc.getRenamedFrom() != null);
        final String refLGName = isRename ? lgDesc.getRenamedFrom() : lgDesc.getName();
        lgDesc.setRenamedFrom(null);
        if (isRename && (reference == null)) {
            throw new InvalidLayoutException(String
                    .format("Invalid rename: no reference table layout for locality group '%s'.", refLGName));
        }
        final LocalityGroupLayout refLGLayout = (reference != null) ? reference.mLocalityGroupMap.get(refLGName)
                : null;
        if (isRename && (refLGLayout == null)) {
            throw new InvalidLayoutException(
                    String.format("Invalid rename: cannot find reference locality group '%s'.", refLGName));
        }

        final ColumnId refLGId = refLGIdMap.remove(refLGName);

        if (lgDesc.getDelete()) {
            // This locality group is deleted:
            if (refLGId == null) {
                throw new InvalidLayoutException(String.format(
                        "Attempting to delete locality group '%s' unknown in reference layout.", refLGName));
            }
            itLGDesc.remove();
            continue;
        }

        // BloomType, block_size were introduced in version 1.2.
        if (Versions.BLOCK_SIZE_LAYOUT_VERSION.compareTo(mLayoutVersion) > 0) {
            if (lgDesc.getBlockSize() != null) {
                // Cannot use max_filesize if this is the case.
                throw new InvalidLayoutException("Support for specifying block_size begins with layout version "
                        + Versions.BLOCK_SIZE_LAYOUT_VERSION);
            }
            if (lgDesc.getBloomType() != null) {
                // Cannot use bloom_type if this is the case.
                throw new InvalidLayoutException("Support for specifying bloom_type begins with layout version "
                        + Versions.BLOCK_SIZE_LAYOUT_VERSION);
            }
        } else {
            if (lgDesc.getBlockSize() != null && lgDesc.getBlockSize() <= 0) {
                throw new InvalidLayoutException("block_size must be greater than 0");
            }
        }

        final LocalityGroupLayout lgLayout = new LocalityGroupLayout(lgDesc, refLGLayout);
        localityGroups.add(lgLayout);
        for (String lgName : lgLayout.getNames()) {
            Preconditions.checkState(lgMap.put(lgName, lgLayout) == null,
                    "Duplicate locality group name: " + lgName);
        }

        if (lgLayout.getId() != null) {
            final String previous = idMap.put(lgLayout.getId(), lgLayout.getName());
            Preconditions.checkState(previous == null,
                    String.format("Duplicate locality group ID '%s' associated to '%s' and '%s'.",
                            lgLayout.getId(), lgLayout.getName(), previous));
        } else {
            unassigned.add(lgLayout);
        }

        families.addAll(lgLayout.getFamilies());
        for (FamilyLayout familyLayout : lgLayout.getFamilies()) {
            for (String familyName : familyLayout.getNames()) {
                if (null != familyMap.put(familyName, familyLayout)) {
                    throw new InvalidLayoutException(
                            String.format("Layout for table '%s' contains duplicate family name '%s'.",
                                    getName(), familyName));
                }
            }

            if (familyLayout.isMapType()) {
                Preconditions.checkState(columnNames.add(KijiColumnName.create(familyLayout.getName(), null)));
            }

            for (ColumnLayout columnLayout : familyLayout.getColumns()) {
                for (String columnName : columnLayout.getNames()) {
                    final KijiColumnName column = KijiColumnName.create(familyLayout.getName(), columnName);
                    if (null != columnMap.put(column, columnLayout)) {
                        throw new InvalidLayoutException(String.format(
                                "Layout for table '%s' contains duplicate column '%s'.", getName(), column));
                    }
                }
                Preconditions.checkState(
                        columnNames.add(KijiColumnName.create(familyLayout.getName(), columnLayout.getName())));
            }
        }
    }

    if (!refLGIdMap.isEmpty()) {
        throw new InvalidLayoutException(String.format("Missing descriptor(s) for locality group(s): %s.",
                Joiner.on(",").join(refLGIdMap.keySet())));
    }

    mLocalityGroups = ImmutableList.copyOf(localityGroups);
    mLocalityGroupMap = ImmutableMap.copyOf(lgMap);

    mFamilies = ImmutableList.copyOf(families);
    mFamilyMap = ImmutableMap.copyOf(familyMap);

    mColumnNames = ImmutableSet.copyOf(columnNames);

    // Assign IDs to locality groups:
    int nextColumnId = 1;
    for (LocalityGroupLayout localityGroup : unassigned) {
        Preconditions.checkState(localityGroup.getId() == null);
        while (true) {
            final ColumnId columnId = new ColumnId(nextColumnId);
            nextColumnId += 1;
            if (!idMap.containsKey(columnId)) {
                localityGroup.setId(columnId);
                idMap.put(columnId, localityGroup.getName());
                break;
            }
        }
    }

    mLocalityGroupIdNameMap = ImmutableBiMap.copyOf(idMap);
}