/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.accumulo.server.replication; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.apache.accumulo.core.client.IteratorSetting; import org.apache.accumulo.core.client.IteratorSetting.Column; import org.apache.accumulo.core.client.impl.BaseIteratorEnvironment; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.iterators.Combiner; import org.apache.accumulo.core.iterators.DevNull; import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; import org.apache.accumulo.core.replication.ReplicationSchema.StatusSection; import org.apache.accumulo.server.replication.proto.Replication.Status; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class StatusCombinerTest { private StatusCombiner combiner; private Key key; private Status.Builder builder; private static class TestIE extends BaseIteratorEnvironment { @Override public IteratorScope getIteratorScope() { return IteratorScope.scan; } } @Before public void initCombiner() throws IOException { key = new Key(); combiner = new StatusCombiner(); builder = Status.newBuilder(); IteratorSetting cfg = new IteratorSetting(50, StatusCombiner.class); Combiner.setColumns(cfg, Collections.singletonList(new Column(StatusSection.NAME))); combiner.init(new DevNull(), cfg.getOptions(), new TestIE()); } @Test public void returnsSameObject() { Status status = StatusUtil.ingestedUntil(10); // When combining only one message, we should get back the same instance Status ret = combiner.typedReduce(key, Collections.singleton(status).iterator()); Assert.assertEquals(status, ret); Assert.assertTrue(status == ret); } @Test public void newStatusWithNewIngest() { Status orig = StatusUtil.fileCreated(100); Status status = StatusUtil.replicatedAndIngested(10, 20); Status ret = combiner.typedReduce(key, Arrays.asList(orig, status).iterator()); Assert.assertEquals(10l, ret.getBegin()); Assert.assertEquals(20l, ret.getEnd()); Assert.assertEquals(100l, ret.getCreatedTime()); Assert.assertEquals(false, ret.getClosed()); } @Test public void newStatusWithNewIngestSingleBuilder() { Status orig = StatusUtil.fileCreated(100); Status status = StatusUtil.replicatedAndIngested(builder, 10, 20); Status ret = combiner.typedReduce(key, Arrays.asList(orig, status).iterator()); Assert.assertEquals(10l, ret.getBegin()); Assert.assertEquals(20l, ret.getEnd()); Assert.assertEquals(100l, ret.getCreatedTime()); Assert.assertEquals(false, ret.getClosed()); } @Test public void commutativeNewFile() { Status newFile = StatusUtil.fileCreated(100), firstSync = StatusUtil.ingestedUntil(100), secondSync = StatusUtil.ingestedUntil(200); Status order1 = combiner.typedReduce(key, Arrays.asList(newFile, firstSync, secondSync).iterator()), order2 = combiner.typedReduce(key, Arrays.asList(secondSync, firstSync, newFile).iterator()); Assert.assertEquals(order1, order2); } @Test public void commutativeNewFileSingleBuilder() { Status newFile = StatusUtil.fileCreated(100), firstSync = StatusUtil.ingestedUntil(builder, 100), secondSync = StatusUtil.ingestedUntil(builder, 200); Status order1 = combiner.typedReduce(key, Arrays.asList(newFile, firstSync, secondSync).iterator()), order2 = combiner.typedReduce(key, Arrays.asList(secondSync, firstSync, newFile).iterator()); Assert.assertEquals(order1, order2); } @Test public void commutativeNewUpdates() { Status newFile = StatusUtil.fileCreated(100), firstSync = StatusUtil.ingestedUntil(100), secondSync = StatusUtil.ingestedUntil(200); Status order1 = combiner.typedReduce(key, Arrays.asList(newFile, firstSync, secondSync).iterator()), order2 = combiner.typedReduce(key, Arrays.asList(newFile, secondSync, firstSync).iterator()); Assert.assertEquals(order1, order2); } @Test public void commutativeNewUpdatesSingleBuilder() { Status newFile = StatusUtil.fileCreated(100), firstSync = StatusUtil.ingestedUntil(builder, 100), secondSync = StatusUtil.ingestedUntil(builder, 200); Status order1 = combiner.typedReduce(key, Arrays.asList(newFile, firstSync, secondSync).iterator()), order2 = combiner.typedReduce(key, Arrays.asList(newFile, secondSync, firstSync).iterator()); Assert.assertEquals(order1, order2); } @Test public void commutativeWithClose() { Status newFile = StatusUtil.fileCreated(100), closed = StatusUtil.fileClosed(), secondSync = StatusUtil.ingestedUntil(200); Status order1 = combiner.typedReduce(key, Arrays.asList(newFile, closed, secondSync).iterator()), order2 = combiner.typedReduce(key, Arrays.asList(newFile, secondSync, closed).iterator()); Assert.assertEquals(order1, order2); } @Test public void commutativeWithCloseSingleBuilder() { Status newFile = StatusUtil.fileCreated(100), closed = StatusUtil.fileClosed(), secondSync = StatusUtil.ingestedUntil(builder, 200); Status order1 = combiner.typedReduce(key, Arrays.asList(newFile, closed, secondSync).iterator()), order2 = combiner.typedReduce(key, Arrays.asList(newFile, secondSync, closed).iterator()); Assert.assertEquals(order1, order2); } @Test public void commutativeWithMultipleUpdates() { Status newFile = StatusUtil.fileCreated(100), update1 = StatusUtil.ingestedUntil(100), update2 = StatusUtil.ingestedUntil(200), repl1 = StatusUtil .replicated(50), repl2 = StatusUtil.replicated(150); Status order1 = combiner.typedReduce(key, Arrays.asList(newFile, update1, repl1, update2, repl2).iterator()); // Got all replication updates before ingest updates Status permutation = combiner.typedReduce(key, Arrays.asList(newFile, repl1, update1, repl2, update2).iterator()); Assert.assertEquals(order1, permutation); // All replications before updates permutation = combiner.typedReduce(key, Arrays.asList(newFile, repl1, repl2, update1, update2).iterator()); Assert.assertEquals(order1, permutation); // All updates before replications permutation = combiner.typedReduce(key, Arrays.asList(newFile, update1, update2, repl1, repl2, update1, update2).iterator()); Assert.assertEquals(order1, permutation); } @Test public void commutativeWithMultipleUpdatesSingleBuilder() { Status newFile = StatusUtil.fileCreated(100), update1 = StatusUtil.ingestedUntil(builder, 100), update2 = StatusUtil.ingestedUntil(builder, 200), repl1 = StatusUtil .replicated(builder, 50), repl2 = StatusUtil.replicated(builder, 150); Status order1 = combiner.typedReduce(key, Arrays.asList(newFile, update1, repl1, update2, repl2).iterator()); // Got all replication updates before ingest updates Status permutation = combiner.typedReduce(key, Arrays.asList(newFile, repl1, update1, repl2, update2).iterator()); Assert.assertEquals(order1, permutation); // All replications before updates permutation = combiner.typedReduce(key, Arrays.asList(newFile, repl1, repl2, update1, update2).iterator()); Assert.assertEquals(order1, permutation); // All updates before replications permutation = combiner.typedReduce(key, Arrays.asList(newFile, update1, update2, repl1, repl2).iterator()); Assert.assertEquals(order1, permutation); } @Test public void duplicateStatuses() { Status newFile = StatusUtil.fileCreated(100), update1 = StatusUtil.ingestedUntil(builder, 100), update2 = StatusUtil.ingestedUntil(builder, 200), repl1 = StatusUtil .replicated(builder, 50), repl2 = StatusUtil.replicated(builder, 150); Status order1 = combiner.typedReduce(key, Arrays.asList(newFile, update1, repl1, update2, repl2).iterator()); // Repeat the same thing more than once Status permutation = combiner.typedReduce(key, Arrays.asList(newFile, repl1, update1, update1, repl2, update2, update2).iterator()); Assert.assertEquals(order1, permutation); } @Test public void fileClosedTimePropagated() { Status stat1 = Status.newBuilder().setBegin(10).setEnd(20).setClosed(true).setInfiniteEnd(false).setCreatedTime(50).build(); Status stat2 = Status.newBuilder().setBegin(10).setEnd(20).setClosed(true).setInfiniteEnd(false).build(); Status combined = combiner.typedReduce(key, Arrays.asList(stat1, stat2).iterator()); Assert.assertEquals(stat1, combined); } @Test public void fileClosedTimeChoosesEarliestIgnoringDefault() { Status stat1 = Status.newBuilder().setBegin(10).setEnd(20).setClosed(true).setInfiniteEnd(false).setCreatedTime(50).build(); Status stat2 = Status.newBuilder().setBegin(10).setEnd(20).setClosed(true).setInfiniteEnd(false).setCreatedTime(100).build(); Status combined = combiner.typedReduce(key, Arrays.asList(stat1, stat2).iterator()); Assert.assertEquals(stat1, combined); Status stat3 = Status.newBuilder().setBegin(10).setEnd(20).setClosed(true).setInfiniteEnd(false).setCreatedTime(100).build(); Status combined2 = combiner.typedReduce(key, Arrays.asList(combined, stat3).iterator()); Assert.assertEquals(combined, combined2); } @Test public void testCombination() { List<Status> status = new ArrayList<>(); long time = System.currentTimeMillis(); status.add(StatusUtil.fileCreated(time)); status.add(StatusUtil.openWithUnknownLength()); status.add(StatusUtil.fileClosed()); Status combined = combiner.typedReduce(new Key("row"), status.iterator()); Assert.assertEquals(time, combined.getCreatedTime()); Assert.assertTrue(combined.getInfiniteEnd()); Assert.assertTrue(combined.getClosed()); } }