Make DnsWriter truly atomic

Right now - if there's an error during DnsWriter.publish*, all the publish from
before that error will be committed, while all the publish after that error
will not.

More than that - in some writers partial publishes can be committed, depending
on implementation.

This defines a new contract that publish* are only committed when .commit is
called. That way any error will simply mean no publish is committed.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=165708063
This commit is contained in:
guyben 2017-08-18 08:27:34 -07:00 committed by Ben McIlwain
parent fcb554947c
commit d5ac03aae4
8 changed files with 204 additions and 90 deletions

View file

@ -15,6 +15,7 @@
package google.registry.dns.writer.clouddns;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import com.google.api.client.googleapis.json.GoogleJsonError.ErrorInfo;
@ -84,6 +85,8 @@ public class CloudDnsWriter implements DnsWriter {
private final ImmutableMap.Builder<String, ImmutableSet<ResourceRecordSet>>
desiredRecordsBuilder = new ImmutableMap.Builder<>();
private boolean committed = false;
@Inject
CloudDnsWriter(
Dns dnsConnection,
@ -270,12 +273,14 @@ public class CloudDnsWriter implements DnsWriter {
* representation built via this writer.
*/
@Override
public void close() {
close(desiredRecordsBuilder.build());
public void commit() {
checkState(!committed, "commit() has already been called");
committed = true;
commit(desiredRecordsBuilder.build());
}
@VisibleForTesting
void close(ImmutableMap<String, ImmutableSet<ResourceRecordSet>> desiredRecords) {
void commit(ImmutableMap<String, ImmutableSet<ResourceRecordSet>> desiredRecords) {
retrier.callWithRetry(getMutateZoneCallback(desiredRecords), ZoneStateException.class);
logger.info("Wrote to Cloud DNS");
}