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

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

Introduction

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

Prototype

boolean isEmpty();

Source Link

Document

Returns true if this map contains no key-value mappings.

Usage

From source file:org.opencb.opencga.storage.mongodb.variant.adaptors.VariantMongoDBAdaptor.java

/**
 * Fills the missing genotype values for the new loaded samples.
 * Missing data is which was present in the database but not in the input file.
 * Data present in the file but not in the database is added during the {@link #insert} step.
 * <p>/*from w  w  w . j  av a  2 s  . c o m*/
 * +--------+---------+
 * | Loaded | NewFile |
 * +--------+--------+---------+
 * | 10:A:T | DATA   |         |   <- Missing data to be filled
 * +--------+--------+---------+
 * | 20:C:T |        | DATA    |   <- Missing data already filled in the {@link #insert} step.
 * +--------+--------+---------+
 *
 * @param fileId             Loading File ID
 * @param chromosomes        Chromosomes covered by the current file
 * @param fileSampleIds      FileSampleIds
 * @param studyConfiguration StudyConfiguration
 * @return WriteResult
 */
QueryResult<UpdateResult> fillFileGaps(int fileId, List<String> chromosomes, List<Integer> fileSampleIds,
        StudyConfiguration studyConfiguration) {

    // { "studies.sid" : <studyId>, "studies.files.fid" : { $ne : <fileId> } },
    // { $push : {
    //      "studies.$.gt.?/?" : {$each : [ <fileSampleIds> ] }
    // } }
    if (studyConfiguration.getAttributes().getAsStringList(DEFAULT_GENOTYPE.key(), "")
            .equals(Collections.singletonList(DocumentToSamplesConverter.UNKNOWN_GENOTYPE))
    //                && studyConfiguration.getAttributes().getAsStringList(VariantStorageEngine.Options.EXTRA_GENOTYPE_FIELDS.key()).isEmpty()
    ) {
        // Check if the default genotype is the unknown genotype. In that case, is not required to fill missing genotypes.
        // Previously, also checks if there where EXTRA_GENOTYPE_FIELDS like DP:AD,... . In that case, those arrays had to be filled.
        logger.debug("Do not need fill gaps. DefaultGenotype is UNKNOWN_GENOTYPE({}).",
                DocumentToSamplesConverter.UNKNOWN_GENOTYPE);
        return new QueryResult<>();
    } else if (studyConfiguration.getAttributes().getBoolean(
            VariantStorageEngine.Options.EXCLUDE_GENOTYPES.key(),
            VariantStorageEngine.Options.EXCLUDE_GENOTYPES.defaultValue())) {
        // Check if the genotypes are not required. In that case, no fillGaps is needed
        logger.debug("Do not need fill gaps. Exclude genotypes.");
        return new QueryResult<>();
    } else {
        BiMap<String, Integer> indexedSamples = StudyConfiguration.getIndexedSamples(studyConfiguration);
        if (indexedSamples.isEmpty() || indexedSamples.values().equals(new HashSet<>(fileSampleIds))) {
            // If the loaded samples match with the current samples means that there where no other samples loaded.
            // There were no gaps, so it is not needed to fill anything.
            logger.debug("Do not need fill gaps. First sample batch.");
            return new QueryResult<>();
        }
    }
    logger.debug("Do fill gaps.");

    Document query = new Document();
    if (chromosomes != null && !chromosomes.isEmpty()) {
        query.put(DocumentToVariantConverter.CHROMOSOME_FIELD, new Document("$in", chromosomes));
    }

    query.put(DocumentToVariantConverter.STUDIES_FIELD, new Document("$elemMatch",
            new Document(DocumentToStudyVariantEntryConverter.STUDYID_FIELD, studyConfiguration.getStudyId())
                    .append(DocumentToStudyVariantEntryConverter.FILES_FIELD + "."
                            + DocumentToStudyVariantEntryConverter.FILEID_FIELD, new Document("$ne", fileId))));

    Document push = new Document().append(DocumentToVariantConverter.STUDIES_FIELD + ".$."
            + DocumentToStudyVariantEntryConverter.GENOTYPES_FIELD + "."
            + DocumentToSamplesConverter.UNKNOWN_GENOTYPE, new Document("$each", fileSampleIds));

    //        List<Integer> loadedSamples = getLoadedSamples(fileId, studyConfiguration);
    //        List<Object> missingOtherValues = new ArrayList<>(fileSampleIds.size());
    //        for (int size = fileSampleIds.size(); size > 0; size--) {
    //            missingOtherValues.add(DBObjectToSamplesConverter.UNKNOWN_FIELD);
    //        }
    //        List<String> extraFields = studyConfiguration.getAttributes()
    //                .getAsStringList(VariantStorageEngine.Options.EXTRA_GENOTYPE_FIELDS.key());
    //        for (String extraField : extraFields) {
    //            push.put(DBObjectToVariantConverter.STUDIES_FIELD + ".$." + extraField.toLowerCase(),
    //                    new Document("$each", missingOtherValues).append("$position", loadedSamples.size())
    //            );
    //        }

    Document update = new Document("$push", push);

    QueryOptions queryOptions = new QueryOptions(MULTI, true);
    logger.debug("FillGaps find : {}", query);
    logger.debug("FillGaps update : {}", update);
    return variantsCollection.update(query, update, queryOptions);
}

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.
 *//*from  w w  w.j  ava2s  .  com*/
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 www  . j a  v a2  s .com*/
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);
}