/*
* ToroDB
* Copyright © 2014 8Kdata Technology (www.8kdata.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.torodb.metainfo.cache.mvcc;
import com.torodb.core.transaction.metainf.ImmutableMetaCollection;
import com.torodb.core.transaction.metainf.ImmutableMetaDatabase;
import com.torodb.core.transaction.metainf.ImmutableMetaDocPart;
import com.torodb.core.transaction.metainf.ImmutableMetaDocPartIndexColumn;
import com.torodb.core.transaction.metainf.ImmutableMetaField;
import com.torodb.core.transaction.metainf.ImmutableMetaIdentifiedDocPartIndex;
import com.torodb.core.transaction.metainf.ImmutableMetaIndex;
import com.torodb.core.transaction.metainf.ImmutableMetaIndexField;
import com.torodb.core.transaction.metainf.ImmutableMetaScalar;
import com.torodb.core.transaction.metainf.ImmutableMetaSnapshot;
import com.torodb.core.transaction.metainf.MetaCollection;
import com.torodb.core.transaction.metainf.MetaDatabase;
import com.torodb.core.transaction.metainf.MetaDocPart;
import com.torodb.core.transaction.metainf.MetaElementState;
import com.torodb.core.transaction.metainf.MetaField;
import com.torodb.core.transaction.metainf.MetaIdentifiedDocPartIndex;
import com.torodb.core.transaction.metainf.MetaIndex;
import com.torodb.core.transaction.metainf.MetaScalar;
import com.torodb.core.transaction.metainf.MutableMetaCollection;
import com.torodb.core.transaction.metainf.MutableMetaDatabase;
import com.torodb.core.transaction.metainf.MutableMetaDocPart;
import com.torodb.core.transaction.metainf.MutableMetaIndex;
import com.torodb.core.transaction.metainf.MutableMetaSnapshot;
import com.torodb.core.transaction.metainf.UnmergeableException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.jooq.lambda.tuple.Tuple2;
import java.util.Iterator;
import java.util.Optional;
/**
*
*/
public class SnapshotMerger {
private final ImmutableMetaSnapshot oldSnapshot;
private final MutableMetaSnapshot newSnapshot;
public SnapshotMerger(ImmutableMetaSnapshot oldSnapshot, MutableMetaSnapshot newSnapshot) {
this.oldSnapshot = oldSnapshot;
this.newSnapshot = newSnapshot;
}
public ImmutableMetaSnapshot.Builder merge() throws UnmergeableException {
ImmutableMetaSnapshot.Builder builder = new ImmutableMetaSnapshot.Builder(oldSnapshot);
Iterable<Tuple2<MutableMetaDatabase, MetaElementState>> changes = newSnapshot
.getModifiedDatabases();
for (Tuple2<MutableMetaDatabase, MetaElementState> change : changes) {
merge(builder, change.v1(), change.v2());
}
return builder;
}
private void merge(ImmutableMetaSnapshot.Builder parentBuilder, MutableMetaDatabase newDb,
MetaElementState newState) throws UnmergeableException {
ImmutableMetaDatabase byName = oldSnapshot.getMetaDatabaseByName(newDb.getName());
ImmutableMetaDatabase byId = oldSnapshot.getMetaDatabaseByIdentifier(newDb.getIdentifier());
switch (newState) {
default:
case NOT_CHANGED:
case NOT_EXISTENT:
throw new AssertionError("A modification was expected, but the new state is " + newState);
case ADDED:
case MODIFIED: {
if (byName != byId) {
throw createUnmergeableException(newDb, byName, byId);
}
if (byName == null && byId == null) {
parentBuilder.put(newDb.immutableCopy());
return;
}
assert byName != null;
assert byId != null;
ImmutableMetaDatabase.Builder childBuilder = new ImmutableMetaDatabase.Builder(byId);
for (Tuple2<MutableMetaCollection, MetaElementState> modifiedCollection : newDb
.getModifiedCollections()) {
merge(newDb, byId, childBuilder, modifiedCollection.v1(), modifiedCollection.v2());
}
parentBuilder.put(childBuilder);
break;
}
case REMOVED: {
if (byName != byId) {
/*
* The backend transaction will remove by id, but it is referencing another name on the
* current snapshot, so the final state will be inconsistent. It is better to fail.
*/
throw createUnmergeableException(newDb, byName, byId);
}
if (byName == null && byId == null) {
/*
* it has been removed on another transaction or created and removed on the current one.
* No change must be done
*/
return;
}
assert byName != null;
assert byId != null;
/*
* In this case, we can delegate on the backend transaction check. If it thinks everything
* is fine, we can remove the element. If it thinks there is an error, then we have to
* rollback the transaction.
*/
parentBuilder.remove(byName);
}
}
}
private void merge(MetaDatabase newStructure, ImmutableMetaDatabase oldStructure,
ImmutableMetaDatabase.Builder parentBuilder,
MutableMetaCollection newCol, MetaElementState newState) throws UnmergeableException {
ImmutableMetaCollection byName = oldStructure.getMetaCollectionByName(newCol.getName());
ImmutableMetaCollection byId = oldStructure
.getMetaCollectionByIdentifier(newCol.getIdentifier());
switch (newState) {
default:
case NOT_CHANGED:
case NOT_EXISTENT:
throw new AssertionError("A modification was expected, but the new state is " + newState);
case ADDED:
case MODIFIED: {
if (byName != byId) {
throw createUnmergeableException(oldStructure, newCol, byName, byId);
}
if (byName == null && byId == null) {
parentBuilder.put(newCol.immutableCopy());
return;
}
assert byName != null;
assert byId != null;
ImmutableMetaCollection.Builder childBuilder = new ImmutableMetaCollection.Builder(byId);
for (MutableMetaDocPart modifiedDocPart : newCol.getModifiedMetaDocParts()) {
merge(newStructure, oldStructure, newCol, byId, childBuilder, modifiedDocPart);
}
for (Tuple2<MutableMetaIndex, MetaElementState> modifiedIndex : newCol
.getModifiedMetaIndexes()) {
merge(oldStructure, newCol, byId, childBuilder, modifiedIndex.v1(), modifiedIndex.v2());
}
parentBuilder.put(childBuilder);
break;
}
case REMOVED: {
if (byName != byId) {
/*
* The backend transaction will remove by id, but it is referencing another name on the
* current snapshot, so the final state will be inconsistent. It is better to fail.
*/
throw createUnmergeableException(oldStructure, newCol, byName, byId);
}
if (byName == null && byId == null) {
/*
* it has been removed on another transaction or created and removed on the current one.
* No change must be done
*/
return;
}
assert byName != null;
assert byId != null;
/*
* In this case, we can delegate on the backend transaction check. If it thinks everything
* is fine, we can remove the element. If it thinks there is an error, then we have to
* rollback the transaction.
*/
parentBuilder.remove(byName);
}
}
}
@SuppressWarnings("checkstyle:LineLength")
private void merge(MetaDatabase newDb, MetaDatabase oldDb, MutableMetaCollection newStructure,
ImmutableMetaCollection oldStructure,
ImmutableMetaCollection.Builder parentBuilder, MutableMetaDocPart changed) throws
UnmergeableException {
ImmutableMetaDocPart byRef = oldStructure.getMetaDocPartByTableRef(changed.getTableRef());
ImmutableMetaDocPart byId = oldStructure.getMetaDocPartByIdentifier(changed.getIdentifier());
if (byRef != byId) {
throw createUnmergeableException(oldDb, oldStructure, changed, byRef, byId);
}
if (byRef == null && byId == null) {
parentBuilder.put(changed.immutableCopy());
return;
}
assert byRef != null;
assert byId != null;
ImmutableMetaDocPart.Builder childBuilder = new ImmutableMetaDocPart.Builder(byId);
for (ImmutableMetaField addedMetaField : changed.getAddedMetaFields()) {
merge(oldDb, newStructure, oldStructure, changed, byId, childBuilder, addedMetaField);
}
for (ImmutableMetaScalar addedMetaScalar : changed.getAddedMetaScalars()) {
merge(oldDb, oldStructure, byId, childBuilder, addedMetaScalar);
}
for (Tuple2<ImmutableMetaIdentifiedDocPartIndex, MetaElementState> addedMetaDocPartIndex : changed.getModifiedMetaDocPartIndexes()) {
merge(oldDb, newStructure, oldStructure, changed, byId, childBuilder, addedMetaDocPartIndex
.v1(), addedMetaDocPartIndex.v2());
}
parentBuilder.put(childBuilder);
}
private void merge(MetaDatabase oldDb, MutableMetaCollection newCol, MetaCollection oldCol,
MutableMetaDocPart newStructure, ImmutableMetaDocPart oldStructure,
ImmutableMetaDocPart.Builder parentBuilder, ImmutableMetaField changed) throws
UnmergeableException {
ImmutableMetaField byNameAndType = oldStructure.getMetaFieldByNameAndType(changed.getName(),
changed.getType());
ImmutableMetaField byId = oldStructure.getMetaFieldByIdentifier(changed.getIdentifier());
if (byNameAndType != byId) {
throw createUnmergeableException(oldDb, oldCol, oldStructure, changed, byNameAndType, byId);
}
if (byNameAndType == null && byId == null) {
Optional<? extends MetaIndex> oldMissedIndex = newCol.getAnyMissedIndex(oldCol, newStructure,
oldStructure, changed);
if (oldMissedIndex.isPresent()) {
throw createUnmergeableExceptionForMissing(oldDb, oldCol, oldStructure, changed,
oldMissedIndex.get());
}
parentBuilder.put(changed);
}
}
private void merge(MetaDatabase db, MetaCollection col, ImmutableMetaDocPart oldStructure,
ImmutableMetaDocPart.Builder parentBuilder, ImmutableMetaScalar changed) {
MetaScalar byId = oldStructure.getScalar(changed.getIdentifier());
MetaScalar byType = oldStructure.getScalar(changed.getType());
if (byType != byId) {
throw createUnmergeableException(db, col, oldStructure, changed, byType, byId);
}
if (byType == null && byId == null) {
parentBuilder.put(changed);
}
}
@SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
private void merge(MetaDatabase oldDb, MutableMetaCollection newCol,
ImmutableMetaCollection oldCol, MetaDocPart newStructure, ImmutableMetaDocPart oldStructure,
ImmutableMetaDocPart.Builder parentBuilder, ImmutableMetaIdentifiedDocPartIndex changed,
MetaElementState newState) throws UnmergeableException {
ImmutableMetaIdentifiedDocPartIndex byId = oldStructure.getMetaDocPartIndexByIdentifier(changed
.getIdentifier());
ImmutableMetaIdentifiedDocPartIndex bySameColumns = oldStructure.streamIndexes()
.filter(oldDocPartIndex -> oldDocPartIndex.hasSameColumns(changed))
.findAny()
.orElse(null);
switch (newState) {
default:
case NOT_CHANGED:
case NOT_EXISTENT:
throw new AssertionError("A modification was expected, but the new state is " + newState);
case ADDED:
case MODIFIED: {
Optional<? extends MetaIndex> anyRelatedIndex = newCol.getAnyRelatedIndex(oldCol,
newStructure, changed);
if (!anyRelatedIndex.isPresent()) {
throw createUnmergeableExceptionForOrphan(oldDb, oldCol, oldStructure, changed);
}
if (byId == null) {
parentBuilder.put(changed);
return;
}
assert byId != null;
ImmutableMetaIdentifiedDocPartIndex.Builder childBuilder =
new ImmutableMetaIdentifiedDocPartIndex.Builder(byId);
Iterator<ImmutableMetaDocPartIndexColumn> indexColumnIterator = changed.iteratorColumns();
while (indexColumnIterator.hasNext()) {
ImmutableMetaDocPartIndexColumn indexColumn = indexColumnIterator.next();
merge(oldDb, oldCol, oldStructure, byId, childBuilder, indexColumn);
}
parentBuilder.put(childBuilder);
break;
}
case REMOVED: {
Optional<? extends MetaIndex> oldMissedIndex = newCol.getAnyMissedIndex(oldCol, changed);
if (oldMissedIndex.isPresent()) {
throw createUnmergeableExceptionForMissing(oldDb, oldCol, oldStructure, changed,
oldMissedIndex.get());
}
if (byId == null || bySameColumns == null) {
/*
* it has been removed on another transaction or created and removed on the current one.
* No change must be done
*/
return;
}
assert byId != null;
assert bySameColumns != null;
/*
* In this case, we can delegate on the backend transaction check. If it thinks everything
* is fine, we can remove the element. If it thinks there is an error, then we have to
* rollback the transaction.
*/
parentBuilder.remove(byId);
}
}
}
private void merge(MetaDatabase db, MetaCollection col, MetaDocPart docPart,
ImmutableMetaIdentifiedDocPartIndex oldStructure,
ImmutableMetaIdentifiedDocPartIndex.Builder parentBuilder,
ImmutableMetaDocPartIndexColumn changed) throws UnmergeableException {
ImmutableMetaDocPartIndexColumn byIdentifier = oldStructure
.getMetaDocPartIndexColumnByIdentifier(changed.getIdentifier());
ImmutableMetaDocPartIndexColumn byPosition = oldStructure.getMetaDocPartIndexColumnByPosition(
changed.getPosition());
if (byIdentifier != byPosition) {
throw createUnmergeableException(db, col, docPart, oldStructure, changed, byIdentifier,
byPosition);
}
if (byIdentifier == null && byPosition == null) {
parentBuilder.add(changed);
}
}
@SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
private void merge(MetaDatabase oldDb, MutableMetaCollection newStructure,
ImmutableMetaCollection oldStructure,
ImmutableMetaCollection.Builder parentBuilder, MutableMetaIndex changed,
MetaElementState newState) throws UnmergeableException {
ImmutableMetaIndex byName = oldStructure.getMetaIndexByName(changed.getName());
switch (newState) {
default:
case NOT_CHANGED:
case NOT_EXISTENT:
throw new AssertionError("A modification was expected, but the new state is " + newState);
case ADDED:
case MODIFIED: {
Optional<? extends MetaIndex> anyConflictingIndex = newStructure.getAnyConflictingIndex(
oldStructure, changed);
if (anyConflictingIndex.isPresent()) {
throw createUnmergeableException(oldDb, oldStructure, changed, anyConflictingIndex.get());
}
Optional<? extends MetaDocPart> anyDocPartWithMissingDocPartIndex =
newStructure.getAnyDocPartWithMissedDocPartIndex(oldStructure, changed);
if (anyDocPartWithMissingDocPartIndex.isPresent()) {
throw createUnmergeableExceptionForMissing(oldDb, oldStructure, changed,
anyDocPartWithMissingDocPartIndex.get());
}
if (byName == null) {
parentBuilder.put(changed.immutableCopy());
return;
}
assert byName != null;
ImmutableMetaIndex.Builder childBuilder = new ImmutableMetaIndex.Builder(byName);
for (ImmutableMetaIndexField addedMetaIndexField : changed.getAddedMetaIndexFields()) {
merge(oldDb, oldStructure, byName, childBuilder, addedMetaIndexField);
}
parentBuilder.put(childBuilder);
break;
}
case REMOVED: {
Optional<? extends MetaIdentifiedDocPartIndex> orphanDocPartIndex = newStructure
.getAnyOrphanDocPartIndex(oldStructure, changed);
if (orphanDocPartIndex.isPresent()) {
throw createUnmergeableExceptionForOrphan(oldDb, oldStructure, changed, orphanDocPartIndex
.get());
}
if (byName == null) {
/*
* it has been removed on another transaction or created and removed on the current one.
* No change must be done
*/
return;
}
assert byName != null;
/*
* In this case, we can delegate on the backend transaction check. If it thinks everything
* is fine, we can remove the element. If it thinks there is an error, then we have to
* rollback the transaction.
*/
parentBuilder.remove(byName);
}
}
}
private void merge(MetaDatabase db, MetaCollection col, ImmutableMetaIndex oldStructure,
ImmutableMetaIndex.Builder parentBuilder, ImmutableMetaIndexField changed) throws
UnmergeableException {
ImmutableMetaIndexField byTableRefAndName = oldStructure.getMetaIndexFieldByTableRefAndName(
changed.getTableRef(), changed.getName());
ImmutableMetaIndexField byPosition = oldStructure.getMetaIndexFieldByPosition(changed
.getPosition());
if (byTableRefAndName != byPosition) {
throw createUnmergeableException(db, col, oldStructure, changed, byTableRefAndName,
byPosition);
}
if (byTableRefAndName == null && byPosition == null) {
parentBuilder.add(changed);
}
}
private UnmergeableException createUnmergeableException(
MetaDatabase newDb, ImmutableMetaDatabase byName, ImmutableMetaDatabase byId) {
if (byName != null) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous database whose name is " + byName.getName()
+ " that has a different id. The previous element id is "
+ byName.getIdentifier() + " and the new one is " + newDb.getIdentifier());
} else {
assert byId != null;
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous database whose id is " + byId.getIdentifier()
+ " that has a different name. The previous element name is "
+ byId.getName() + " and the new one is " + newDb.getName());
}
}
private UnmergeableException createUnmergeableException(
MetaDatabase db,
MutableMetaCollection newCol, ImmutableMetaCollection byName, ImmutableMetaCollection byId) {
if (byName != null) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous collection on " + db + " whose name is "
+ byName.getName() + " that has a different id. The previous "
+ "element id is " + byName.getIdentifier() + " and the new one is "
+ newCol.getIdentifier());
} else {
assert byId != null;
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous collection on " + db + " whose id is "
+ byId.getIdentifier() + " that has a different name. The previous "
+ "element name is " + byId.getName() + " and the new one is "
+ newCol.getIdentifier());
}
}
private UnmergeableException createUnmergeableException(
MetaDatabase db,
MetaCollection col, MutableMetaDocPart changed, ImmutableMetaDocPart byRef,
ImmutableMetaDocPart byId) {
if (byRef != null) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous doc part on " + db + "." + col + " whose ref is "
+ byRef.getTableRef() + " that has a different id. The previous "
+ "element id is " + byRef.getIdentifier() + " and the new one is "
+ changed.getIdentifier());
} else {
assert byId != null;
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous doc part on " + db + "." + col + " whose id is "
+ byId.getIdentifier() + " that has a different ref. The previous "
+ "element ref is " + byId.getTableRef() + " and the new one is "
+ changed.getTableRef());
}
}
private UnmergeableException createUnmergeableException(
MetaDatabase db, MetaCollection col, MetaDocPart docPart, ImmutableMetaField changed,
ImmutableMetaField byNameAndType, ImmutableMetaField byId) {
if (byNameAndType != null) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous field on doc part " + db + "." + col + "." + docPart + " whose "
+ "name is " + byNameAndType.getName() + " and type is "
+ byNameAndType.getType() + " that has a different id. The previous "
+ "element id is " + byNameAndType.getIdentifier() + " and the new "
+ "one is " + changed.getIdentifier());
} else {
assert byId != null;
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous field on doc part " + db.getIdentifier() + "." + col.getIdentifier()
+ "." + docPart.getIdentifier() + " whose id is " + byId.getIdentifier()
+ " that has a different name or "
+ "type. The previous element name is " + byId.getName() + " and its "
+ "type is " + byId.getType() + ". The name of the new one is "
+ changed.getName() + " and its type is " + changed.getType());
}
}
private UnmergeableException createUnmergeableException(
MetaDatabase db, MetaCollection col, MetaDocPart docPart, ImmutableMetaScalar changed,
MetaScalar byType, MetaScalar byId) {
if (byType != null) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous meta scalar on " + db.getIdentifier() + "."
+ col.getIdentifier() + "." + docPart.getIdentifier() + " whose "
+ "type is " + changed.getType() + " but its identifier is "
+ byType.getIdentifier() + ". The identifier of the new one is "
+ changed.getIdentifier()
);
} else {
assert byId != null;
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous meta scalar on " + db.getIdentifier() + "."
+ col.getIdentifier() + "." + docPart.getIdentifier() + " whose "
+ "identifier is " + changed.getIdentifier() + " but its type is "
+ byId.getType() + ". The type of the new one is " + changed.getType()
);
}
}
private UnmergeableException createUnmergeableException(
MetaDatabase db, MetaCollection col, MetaDocPart docPart, MetaIdentifiedDocPartIndex index,
ImmutableMetaDocPartIndexColumn changed,
ImmutableMetaDocPartIndexColumn byIdentifier, ImmutableMetaDocPartIndexColumn byPosition) {
if (byIdentifier != null) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous field on doc part index " + db.getIdentifier() + "." + col
.getIdentifier() + "." + docPart.getIdentifier() + "." + index.getIdentifier() + " whose "
+ "identifier is " + byIdentifier.getIdentifier()
+ " that has a different position. The previous "
+ "element position is " + byIdentifier.getPosition() + " and the new "
+ "one is " + changed.getPosition());
} else {
assert byPosition != null;
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous field on doc part index " + db.getIdentifier() + "." + col
.getIdentifier()
+ "." + docPart.getIdentifier() + "." + index.getIdentifier() + " whose position is "
+ byPosition.getPosition() + " that has a different name or "
+ "type. The previous element identifier is " + byPosition.getIdentifier()
+ ". The name of the new one is " + changed.getIdentifier());
}
}
private UnmergeableException createUnmergeableException(
MetaDatabase db, MetaCollection col, MetaIndex index, ImmutableMetaIndexField changed,
ImmutableMetaIndexField byTableRefAndName, ImmutableMetaIndexField byPosition) {
if (byTableRefAndName != null) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous field on index " + db + "." + col + "." + index + " whose "
+ "tableRef is " + byTableRefAndName.getTableRef() + " and name is "
+ byTableRefAndName.getName() + " that has a different position. The previous "
+ "element position is " + byTableRefAndName.getPosition() + " and the new "
+ "one is " + changed.getPosition());
} else {
assert byPosition != null;
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous field on index " + db + "." + col
+ "." + index + " whose position is " + byPosition.getPosition()
+ " that has a different tableRef or "
+ "name. The previous element tableRef is " + byPosition.getTableRef() + " and its "
+ "name is " + byPosition.getName() + ". The tableRef of the new one is "
+ changed.getTableRef() + " and its name is " + changed.getName());
}
}
private UnmergeableException createUnmergeableException(
MetaDatabase db,
MetaCollection col, MutableMetaIndex changed, MetaIndex oldIndex) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous index on " + db + "." + col + "." + oldIndex
+ " that conflict with new index "
+ changed);
}
private UnmergeableException createUnmergeableExceptionForMissing(
MetaDatabase db,
MetaCollection col, MetaDocPart docPart, MetaField changed, MetaIndex oldMissedIndex) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous index on " + db + "." + col
+ " whose name is " + oldMissedIndex.getName()
+ " associated with new doc part field " + docPart + "."
+ changed + " and the corresponding doc part index has not been created.");
}
private UnmergeableException createUnmergeableExceptionForMissing(
MetaDatabase db, MetaCollection col, MetaDocPart docPart, MetaIdentifiedDocPartIndex changed,
MetaIndex oldMissedIndex) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous doc part index " + db + "." + col + "." + docPart + "."
+ oldMissedIndex
+ " that is compatible with the removed doc part index "
+ db.getIdentifier() + "." + col.getIdentifier() + "." + docPart.getIdentifier() + "."
+ changed.getIdentifier());
}
private UnmergeableException createUnmergeableExceptionForMissing(
MetaDatabase db,
MetaCollection col, MutableMetaIndex changed, MetaDocPart oldDocPartForMissedIndex) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There should be a doc part index on " + db + "." + col + "." + oldDocPartForMissedIndex
+ " associated only with new index "
+ changed + " that has not been created.");
}
private UnmergeableException createUnmergeableExceptionForOrphan(
MetaDatabase db,
MetaCollection col,
MetaDocPart docPart,
MetaIdentifiedDocPartIndex changed) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a new doc part index " + db.getIdentifier() + "." + col.getIdentifier() + "."
+ docPart.getIdentifier() + "." + changed.getIdentifier()
+ " that has no index associated");
}
private UnmergeableException createUnmergeableExceptionForOrphan(
MetaDatabase db,
MetaCollection col,
MutableMetaIndex changed,
MetaIdentifiedDocPartIndex oldOrphanDocPartIndex) {
throw new UnmergeableException(oldSnapshot, newSnapshot,
"There is a previous doc part index on " + db.getIdentifier() + "." + oldOrphanDocPartIndex
.getIdentifier()
+ " associated only with removed index "
+ changed + " that has not been deleted.");
}
}