use of org.projectnessie.versioned.BranchName in project nessie by projectnessie.
the class AbstractMergeTransplant method transplant.
@ParameterizedTest
@ValueSource(ints = { 3, 10, DEFAULT_KEY_LIST_DISTANCE, DEFAULT_KEY_LIST_DISTANCE + 1, 100 })
void transplant(int numCommits) throws Exception {
AtomicInteger unifier = new AtomicInteger();
Function<ByteString, ByteString> metadataUpdater = commitMeta -> ByteString.copyFromUtf8(commitMeta.toStringUtf8() + " transplanted " + unifier.getAndIncrement());
Hash[] commits = mergeTransplant(numCommits, (target, expectedHead, branch, commitHashes, i) -> databaseAdapter.transplant(target, expectedHead, Arrays.asList(commitHashes).subList(0, i + 1), metadataUpdater));
BranchName conflict = BranchName.of("conflict");
// no conflict, when transplanting the commits from against the current HEAD of the
// conflict-branch
Hash noConflictHead = databaseAdapter.hashOnReference(conflict, Optional.empty());
Hash transplanted = databaseAdapter.transplant(conflict, Optional.of(noConflictHead), Arrays.asList(commits), metadataUpdater);
int offset = unifier.get();
try (Stream<CommitLogEntry> log = databaseAdapter.commitLog(transplanted).limit(commits.length)) {
AtomicInteger testOffset = new AtomicInteger(offset);
assertThat(log.map(CommitLogEntry::getMetadata).map(ByteString::toStringUtf8)).containsExactlyElementsOf(IntStream.range(0, commits.length).map(i -> commits.length - i - 1).mapToObj(i -> "commit " + i + " transplanted " + testOffset.decrementAndGet()).collect(Collectors.toList()));
}
// again, no conflict (same as above, just again)
transplanted = databaseAdapter.transplant(conflict, Optional.empty(), Arrays.asList(commits), metadataUpdater);
offset = unifier.get();
try (Stream<CommitLogEntry> log = databaseAdapter.commitLog(transplanted).limit(commits.length)) {
AtomicInteger testOffset = new AtomicInteger(offset);
assertThat(log.map(CommitLogEntry::getMetadata).map(ByteString::toStringUtf8)).containsExactlyElementsOf(IntStream.range(0, commits.length).map(i -> commits.length - i - 1).mapToObj(i -> "commit " + i + " transplanted " + testOffset.decrementAndGet()).collect(Collectors.toList()));
}
assertThatThrownBy(() -> databaseAdapter.transplant(conflict, Optional.empty(), Collections.emptyList(), Function.identity())).isInstanceOf(IllegalArgumentException.class).hasMessage("No hashes to transplant given.");
}
use of org.projectnessie.versioned.BranchName in project nessie by projectnessie.
the class AbstractDatabaseAdapter method transplantAttempt.
/**
* Logic implementation of a transplant-attempt.
*
* @param ctx technical operation context
* @param targetBranch target reference with expected HEAD
* @param expectedHead if present, {@code targetBranch}'s current HEAD must be equal to this value
* @param targetHead current HEAD of {@code targetBranch}
* @param sequenceToTransplant sequential list of commits to transplant from {@code source}
* @param branchCommits consumer for the individual commits to merge
* @param newKeyLists consumer for optimistically written {@link KeyListEntity}s
* @param rewriteMetadata function to rewrite the commit-metadata for copied commits
* @return hash of the last commit-log-entry written to {@code targetBranch}
*/
protected Hash transplantAttempt(OP_CONTEXT ctx, long timeInMicros, BranchName targetBranch, Optional<Hash> expectedHead, Hash targetHead, List<Hash> sequenceToTransplant, Consumer<Hash> branchCommits, Consumer<Hash> newKeyLists, Function<ByteString, ByteString> rewriteMetadata) throws ReferenceNotFoundException, ReferenceConflictException {
if (sequenceToTransplant.isEmpty()) {
throw new IllegalArgumentException("No hashes to transplant given.");
}
// 1. ensure 'expectedHash' is a parent of HEAD-of-'targetBranch' & collect keys
List<CommitLogEntry> targetEntriesReverseChronological = new ArrayList<>();
hashOnRef(ctx, targetHead, targetBranch, expectedHead, targetEntriesReverseChronological::add);
// Exclude the expected-hash on the target-branch from key-collisions check
if (!targetEntriesReverseChronological.isEmpty() && expectedHead.isPresent() && targetEntriesReverseChronological.get(0).getHash().equals(expectedHead.get())) {
targetEntriesReverseChronological.remove(0);
}
Collections.reverse(targetEntriesReverseChronological);
// 2. Collect modified keys.
Set<Key> keysTouchedOnTarget = collectModifiedKeys(targetEntriesReverseChronological);
// 4. ensure 'sequenceToTransplant' is sequential
int[] index = new int[] { sequenceToTransplant.size() - 1 };
Hash lastHash = sequenceToTransplant.get(sequenceToTransplant.size() - 1);
List<CommitLogEntry> commitsToTransplantChronological = takeUntilExcludeLast(readCommitLogStream(ctx, lastHash), e -> {
int i = index[0]--;
if (i == -1) {
return true;
}
if (!e.getHash().equals(sequenceToTransplant.get(i))) {
throw new IllegalArgumentException("Sequence of hashes is not contiguous.");
}
return false;
}).collect(Collectors.toList());
// 5. check for key-collisions
checkForKeyCollisions(ctx, targetHead, keysTouchedOnTarget, commitsToTransplantChronological);
// (no need to verify the global states during a transplant)
// 6. re-apply commits in 'sequenceToTransplant' onto 'targetBranch'
targetHead = copyCommits(ctx, timeInMicros, targetHead, commitsToTransplantChronological, newKeyLists, rewriteMetadata);
// 7. Write commits
commitsToTransplantChronological.stream().map(CommitLogEntry::getHash).forEach(branchCommits);
writeMultipleCommits(ctx, commitsToTransplantChronological);
return targetHead;
}
use of org.projectnessie.versioned.BranchName in project nessie by projectnessie.
the class NamespaceApiImpl method deleteNamespace.
@Override
public void deleteNamespace(NamespaceParams params) throws NessieReferenceNotFoundException, NessieNamespaceNotEmptyException, NessieNamespaceNotFoundException {
BranchName branch = branchFromRefName(params.getRefName());
try {
Namespace namespace = getNamespace(params, branch);
Delete delete = Delete.of(ContentKey.of(namespace.getElements()));
Callable<Void> validator = () -> {
try (Stream<WithType<Key, Type>> keys = getStore().getKeys(branch)) {
if (keys.anyMatch(k -> Namespace.of(k.getValue().getElements()).name().startsWith(params.getNamespace().name()) && k.getType() != Type.NAMESPACE)) {
throw namespaceNotEmptyException(params);
}
}
return null;
};
commit(branch, "delete namespace " + namespace.name(), TreeApiImpl.toOp(delete), validator);
} catch (ReferenceNotFoundException | ReferenceConflictException e) {
throw new NessieReferenceNotFoundException(e.getMessage(), e);
}
}
use of org.projectnessie.versioned.BranchName in project nessie by projectnessie.
the class NamespaceApiImpl method getNamespaces.
@Override
public GetNamespacesResponse getNamespaces(MultipleNamespacesParams params) throws NessieReferenceNotFoundException {
BranchName branch = branchFromRefName(params.getRefName());
try {
Set<Namespace> allNamespaces = Sets.newHashSet(getExplicitlyCreatedNamespaces(params, branch));
List<Namespace> implicitlyCreatedNamespaces = getImplicitlyCreatedNamespaces(params, branch);
allNamespaces.addAll(implicitlyCreatedNamespaces);
return ImmutableGetNamespacesResponse.builder().addAllNamespaces(allNamespaces).build();
} catch (ReferenceNotFoundException e) {
throw refNotFoundException(e);
}
}
use of org.projectnessie.versioned.BranchName in project nessie by projectnessie.
the class NamespaceApiImpl method createNamespace.
@Override
public Namespace createNamespace(NamespaceParams params) throws NessieNamespaceAlreadyExistsException, NessieReferenceNotFoundException {
try {
BranchName branch = branchFromRefName(params.getRefName());
Callable<Void> validator = () -> {
if (getExplicitlyCreatedNamespace(params, branch).isPresent()) {
throw namespaceAlreadyExistsException(params);
}
if (getImplicitlyCreatedNamespace(params, branch).isPresent()) {
throw namespaceAlreadyExistsException(params);
}
return null;
};
Namespace namespace = params.getNamespace();
Put put = Put.of(ContentKey.of(namespace.getElements()), namespace);
commit(branch, "create namespace " + namespace.name(), TreeApiImpl.toOp(put), validator);
return namespace;
} catch (ReferenceNotFoundException | ReferenceConflictException e) {
throw new NessieReferenceNotFoundException(e.getMessage(), e);
}
}
Aggregations