diff --git a/core/src/main/java/org/apache/accumulo/core/metadata/schema/Ample.java b/core/src/main/java/org/apache/accumulo/core/metadata/schema/Ample.java index ce8f32ceb92..47bd5e4d1d7 100644 --- a/core/src/main/java/org/apache/accumulo/core/metadata/schema/Ample.java +++ b/core/src/main/java/org/apache/accumulo/core/metadata/schema/Ample.java @@ -529,6 +529,8 @@ interface ConditionalTabletMutator extends TabletUpdates * Ample provides the following features on top of the conditional writer to help automate diff --git a/server/base/src/main/java/org/apache/accumulo/server/metadata/ConditionalTabletMutatorImpl.java b/server/base/src/main/java/org/apache/accumulo/server/metadata/ConditionalTabletMutatorImpl.java index bd35c007133..34ecdeeebdd 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/metadata/ConditionalTabletMutatorImpl.java +++ b/server/base/src/main/java/org/apache/accumulo/server/metadata/ConditionalTabletMutatorImpl.java @@ -247,6 +247,14 @@ public Ample.ConditionalTabletMutator requireSame(TabletMetadata tabletMetadata, return this; } + @Override + public Ample.ConditionalTabletMutator requireAbsentLogs() { + Preconditions.checkState(updatesEnabled, "Cannot make updates after calling mutate."); + // create a tablet metadata with an empty set of logs and require the same as that + requireSameSingle(TabletMetadata.builder(extent).build(ColumnType.LOGS), ColumnType.LOGS); + return this; + } + @Override public void submit(Ample.RejectionHandler rejectionCheck) { Preconditions.checkState(updatesEnabled, "Cannot make updates after calling mutate."); diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/merge/DeleteTablets.java b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/merge/DeleteTablets.java index f48885d5469..4ef90497e5c 100644 --- a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/merge/DeleteTablets.java +++ b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/merge/DeleteTablets.java @@ -89,7 +89,7 @@ public Repo call(FateId fateId, Manager manager) throws Exception { MergeTablets.validateTablet(tabletMeta, fateId, opid, data.tableId); var tabletMutator = tabletsMutator.mutateTablet(tabletMeta.getExtent()) - .requireOperation(opid).requireAbsentLocation(); + .requireOperation(opid).requireAbsentLocation().requireAbsentLogs(); // do not delete the last tablet if (Objects.equals(tabletMeta.getExtent().endRow(), lastEndRow)) { diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/merge/MergeTablets.java b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/merge/MergeTablets.java index 2b5b9c969c5..d48528a3f79 100644 --- a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/merge/MergeTablets.java +++ b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/merge/MergeTablets.java @@ -153,8 +153,8 @@ public Repo call(FateId fateId, Manager manager) throws Exception { // update the last tablet try (var tabletsMutator = manager.getContext().getAmple().conditionallyMutateTablets()) { var lastExtent = lastTabletMeta.getExtent(); - var tabletMutator = - tabletsMutator.mutateTablet(lastExtent).requireOperation(opid).requireAbsentLocation(); + var tabletMutator = tabletsMutator.mutateTablet(lastExtent).requireOperation(opid) + .requireAbsentLocation().requireAbsentLogs(); // fence the files in the last tablet if needed lastTabletMeta.getFilesMap().forEach((file, dfv) -> { diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/DeleteOperationIds.java b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/DeleteOperationIds.java index dbf0d04f428..9748f2d21ff 100644 --- a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/DeleteOperationIds.java +++ b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/DeleteOperationIds.java @@ -54,7 +54,7 @@ public Repo call(FateId fateId, Manager manager) throws Exception { splitInfo.getTablets().forEach(extent -> { tabletsMutator.mutateTablet(extent).requireOperation(opid).requireAbsentLocation() - .deleteOperation().submit(rejectionHandler); + .requireAbsentLogs().deleteOperation().submit(rejectionHandler); }); var results = tabletsMutator.process(); diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/PreSplit.java b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/PreSplit.java index a973015ddc0..f94afbdb1ef 100644 --- a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/PreSplit.java +++ b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/PreSplit.java @@ -19,6 +19,7 @@ package org.apache.accumulo.manager.tableOps.split; import static org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LOCATION; +import static org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LOGS; import static org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.OPID; import static org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.PREV_ROW; @@ -77,7 +78,7 @@ public long isReady(FateId fateId, Manager manager) throws Exception { // through as quickly as possible. var tabletMetadata = manager.getContext().getAmple().readTablet(splitInfo.getOriginal(), - PREV_ROW, LOCATION, OPID); + PREV_ROW, LOCATION, OPID, LOGS); log.trace("Attempting tablet split {} {} {}", fateId, splitInfo.getOriginal(), tabletMetadata == null ? null : tabletMetadata.getLocation()); @@ -87,28 +88,30 @@ public long isReady(FateId fateId, Manager manager) throws Exception { // tablet no longer exists or is reserved by another operation return 0; } else if (opid.equals(tabletMetadata.getOperationId())) { - if (tabletMetadata.getLocation() == null) { - // the operation id is set and there is no location, so can proceed to split + if (tabletMetadata.getLocation() == null && tabletMetadata.getLogs().isEmpty()) { + // the operation id is set and there is no location or wals, so can proceed to split return 0; } else { - // the operation id was set, but a location is also set wait for it be unset + // the operation id was set, but a location or wals are also set, so wait for them to be + // unset return 1000; } } else { try (var tabletsMutator = manager.getContext().getAmple().conditionallyMutateTablets()) { tabletsMutator.mutateTablet(splitInfo.getOriginal()).requireAbsentOperation() - .requireSame(tabletMetadata, LOCATION).putOperation(opid) + .requireSame(tabletMetadata, LOCATION, LOGS).putOperation(opid) .submit(tmeta -> opid.equals(tmeta.getOperationId())); Map results = tabletsMutator.process(); if (results.get(splitInfo.getOriginal()).getStatus() == Status.ACCEPTED) { log.trace("Successfully set operation id for split {}", fateId); - if (tabletMetadata.getLocation() == null) { - // the operation id was set and there is no location, so can move on + if (tabletMetadata.getLocation() == null && tabletMetadata.getLogs().isEmpty()) { + // the operation id was set and there is no location or wals, so can move on return 0; } else { - // now that the operation id set, generate an event to unload the tablet + // now that the operation id set, generate an event to unload the tablet or recover the + // logs manager.getEventCoordinator().event(splitInfo.getOriginal(), "Set operation id %s on tablet for split", fateId); // the operation id was set, but a location is also set wait for it be unset @@ -129,7 +132,7 @@ public Repo call(FateId fateId, Manager manager) throws Exception { manager.getSplitter().removeSplitStarting(splitInfo.getOriginal()); TabletMetadata tabletMetadata = manager.getContext().getAmple() - .readTablet(splitInfo.getOriginal(), PREV_ROW, LOCATION, OPID); + .readTablet(splitInfo.getOriginal(), PREV_ROW, LOCATION, OPID, LOGS); var opid = TabletOperationId.from(TabletOperationType.SPLITTING, fateId); @@ -149,6 +152,10 @@ public Repo call(FateId fateId, Manager manager) throws Exception { "Tablet unexpectedly had location set %s %s %s", fateId, tabletMetadata.getLocation(), tabletMetadata.getExtent()); + Preconditions.checkState(tabletMetadata.getLogs().isEmpty(), + "Tablet unexpectedly had walogs %s %s %s", fateId, tabletMetadata.getLogs(), + tabletMetadata.getExtent()); + // Create the dir name here for the next step. If the next step fails it will always have the // same dir name each time it runs again making it idempotent. diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/UpdateTablets.java b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/UpdateTablets.java index afc1a77b7a1..2fe3c563999 100644 --- a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/UpdateTablets.java +++ b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/split/UpdateTablets.java @@ -90,6 +90,10 @@ public Repo call(FateId fateId, Manager manager) throws Exception { "Tablet %s unexpectedly has a location %s", splitInfo.getOriginal(), tabletMetadata.getLocation()); + Preconditions.checkState(tabletMetadata.getLogs().isEmpty(), + "Tablet unexpectedly had walogs %s %s %s", fateId, tabletMetadata.getLogs(), + tabletMetadata.getExtent()); + var newTablets = splitInfo.getTablets(); var newTabletsFiles = getNewTabletFiles(newTablets, tabletMetadata, @@ -99,7 +103,6 @@ public Repo call(FateId fateId, Manager manager) throws Exception { // Only update the original tablet after successfully creating the new tablets, this is // important for failure cases where this operation partially runs a then runs again. - updateExistingTablet(fateId, manager, tabletMetadata, opid, newTablets, newTabletsFiles); return new DeleteOperationIds(splitInfo); @@ -216,7 +219,7 @@ private void updateExistingTablet(FateId fateId, Manager manager, TabletMetadata var newExtent = newTablets.last(); var mutator = tabletsMutator.mutateTablet(splitInfo.getOriginal()).requireOperation(opid) - .requireAbsentLocation(); + .requireAbsentLocation().requireAbsentLogs(); mutator.putPrevEndRow(newExtent.prevEndRow());