http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/xsort/SingleBatchSorterTemplate.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/xsort/SingleBatchSorterTemplate.java b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/xsort/SingleBatchSorterTemplate.java new file mode 100644 index 0000000..d518f04 --- /dev/null +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/xsort/SingleBatchSorterTemplate.java @@ -0,0 +1,67 @@ +/** + * 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.drill.exec.physical.impl.xsort; + +import com.google.common.base.Preconditions; +import org.apache.drill.exec.exception.SchemaChangeException; +import org.apache.drill.exec.ops.FragmentContext; +import org.apache.drill.exec.physical.impl.sort.Sorter; +import org.apache.drill.exec.record.RecordBatch; +import org.apache.drill.exec.record.VectorContainer; +import org.apache.drill.exec.record.selection.SelectionVector2; +import org.apache.drill.exec.record.selection.SelectionVector4; +import org.apache.hadoop.util.IndexedSortable; +import org.apache.hadoop.util.QuickSort; + +import javax.inject.Named; + +public abstract class SingleBatchSorterTemplate implements SingleBatchSorter, IndexedSortable{ + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SingleBatchSorterTemplate.class); + + private SelectionVector2 vector2; + + public void setup(FragmentContext context, SelectionVector2 vector2, RecordBatch incoming) throws SchemaChangeException{ + Preconditions.checkNotNull(vector2); + this.vector2 = vector2; + doSetup(context, incoming, null); + } + + @Override + public void sort(SelectionVector2 vector2){ + QuickSort qs = new QuickSort(); + qs.sort(this, 0, vector2.getCount()); + } + + @Override + public void swap(int sv0, int sv1) { + char tmp = vector2.getIndex(sv0); + vector2.setIndex(sv0, vector2.getIndex(sv1)); + vector2.setIndex(sv1, tmp); + } + + @Override + public int compare(int leftIndex, int rightIndex) { + char sv1 = vector2.getIndex(leftIndex); + char sv2 = vector2.getIndex(rightIndex); + return doEval(sv1, sv2); + } + + public abstract void doSetup(@Named("context") FragmentContext context, @Named("incoming") RecordBatch incoming, @Named("outgoing") RecordBatch outgoing); + public abstract int doEval(@Named("leftIndex") char leftIndex, @Named("rightIndex") char rightIndex); + +}
http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/main/java/org/apache/drill/exec/record/ExpandableHyperContainer.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/record/ExpandableHyperContainer.java b/exec/java-exec/src/main/java/org/apache/drill/exec/record/ExpandableHyperContainer.java index 91eb3cb..48f84ab 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/record/ExpandableHyperContainer.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/record/ExpandableHyperContainer.java @@ -25,6 +25,10 @@ import java.util.Iterator; public class ExpandableHyperContainer extends VectorContainer { + public ExpandableHyperContainer() { + super(); + } + public ExpandableHyperContainer(VectorAccessible batch) { super(); if (batch.getSchema().getSelectionVectorMode() == BatchSchema.SelectionVectorMode.FOUR_BYTE) { http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/main/java/org/apache/drill/exec/record/VectorContainer.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/record/VectorContainer.java b/exec/java-exec/src/main/java/org/apache/drill/exec/record/VectorContainer.java index e691f35..8bfb616 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/record/VectorContainer.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/record/VectorContainer.java @@ -71,7 +71,7 @@ public class VectorContainer implements Iterable<VectorWrapper<?>>, VectorAccess * The RecordBatch iterator the contains the batch we should take over. * @return A cloned vector container. */ - public static VectorContainer getTransferClone(RecordBatch incoming) { + public static VectorContainer getTransferClone(VectorAccessible incoming) { VectorContainer vc = new VectorContainer(); for (VectorWrapper<?> w : incoming) { vc.cloneAndTransfer(w); @@ -184,6 +184,9 @@ public class VectorContainer implements Iterable<VectorWrapper<?>>, VectorAccess @Override public int getRecordCount() { + if (recordCount < 0) { + System.out.println(); + } Preconditions.checkState(recordCount != -1, "Record count not set for this vector container"); return recordCount; } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java index 1be5392..1a422ee 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java @@ -17,6 +17,7 @@ */ package org.apache.drill.exec.rpc; +import com.google.common.base.Stopwatch; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufInputStream; import io.netty.channel.Channel; @@ -29,7 +30,9 @@ import io.netty.util.concurrent.GenericFutureListener; import java.io.Closeable; import java.util.Arrays; import java.util.List; +import java.util.concurrent.TimeUnit; +import org.apache.drill.exec.proto.BitControl; import org.apache.drill.exec.proto.GeneralRPCProtos.RpcFailure; import org.apache.drill.exec.proto.GeneralRPCProtos.RpcMode; http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/main/java/org/apache/drill/exec/util/BatchPrinter.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/util/BatchPrinter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/util/BatchPrinter.java index aa68752..fb9521f 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/util/BatchPrinter.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/util/BatchPrinter.java @@ -32,7 +32,7 @@ import java.util.List; * This is a tool for printing the content of record batches to screen. Used for debugging. */ public class BatchPrinter { - public static void printHyperBatch(VectorAccessible batch) { + public static void printHyperBatch(VectorAccessible batch, SelectionVector4 sv4) { List<String> columns = Lists.newArrayList(); List<ValueVector> vectors = Lists.newArrayList(); int numBatches = 0; @@ -41,11 +41,9 @@ public class BatchPrinter { numBatches = vw.getValueVectors().length; } int width = columns.size(); - for (int i = 0; i < numBatches; i++) { - int rows = batch.iterator().next().getValueVectors()[i].getMetadata().getValueCount(); - for (int j = 0; j < rows; j++) { + for (int j = 0; j < sv4.getCount(); j++) { for (VectorWrapper vw : batch) { - Object o = vw.getValueVectors()[i].getAccessor().getObject(j); + Object o = vw.getValueVectors()[sv4.get(j) >>> 16].getAccessor().getObject(j & 65535); if (o instanceof byte[]) { String value = new String((byte[]) o); System.out.printf("| %-15s",value.length() <= 15 ? value : value.substring(0, 14)); @@ -56,7 +54,6 @@ public class BatchPrinter { } System.out.printf("|\n"); } - } System.out.printf("|\n"); } public static void printBatch(VectorAccessible batch) { http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/main/java/org/apache/drill/exec/util/Utilities.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/util/Utilities.java b/exec/java-exec/src/main/java/org/apache/drill/exec/util/Utilities.java new file mode 100644 index 0000000..8efb9e7 --- /dev/null +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/util/Utilities.java @@ -0,0 +1,41 @@ +/** + * 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.drill.exec.util; + +import org.apache.drill.exec.ops.FragmentContext; +import org.apache.drill.exec.proto.ExecProtos; +import org.apache.drill.exec.proto.helper.QueryIdHelper; + +public class Utilities { + public static String getFileNameForQueryFragment(FragmentContext context, String location, String tag) { + /* + * From the context, get the query id, major fragment id, minor fragment id. This will be used as the file name to + * which we will dump the incoming buffer data + */ + ExecProtos.FragmentHandle handle = context.getHandle(); + + String qid = QueryIdHelper.getQueryId(handle.getQueryId()); + + int majorFragmentId = handle.getMajorFragmentId(); + int minorFragmentId = handle.getMinorFragmentId(); + + String fileName = String.format("%s//%s_%s_%s_%s", location, qid, majorFragmentId, minorFragmentId, tag); + + return fileName; + } +} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/main/java/org/apache/drill/exec/vector/BitVector.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/BitVector.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/BitVector.java index 2c028e9..1b4c3da 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/BitVector.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/BitVector.java @@ -120,6 +120,10 @@ public final class BitVector extends BaseDataValueVector implements FixedWidthVe return new TransferImpl(getField().clone(ref)); } + public TransferPair makeTransferPair(ValueVector to) { + return new TransferImpl((BitVector) to); + } + public void transferTo(BitVector target) { target.data = data; @@ -135,6 +139,10 @@ public final class BitVector extends BaseDataValueVector implements FixedWidthVe this.to = new BitVector(field, allocator); } + public TransferImpl(BitVector to) { + this.to = to; + } + public BitVector getTo() { return to; } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/main/java/org/apache/drill/exec/vector/ValueVector.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/ValueVector.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/ValueVector.java index 8dc4298..24e3473 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/ValueVector.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/ValueVector.java @@ -59,6 +59,8 @@ public interface ValueVector extends Closeable { * @return */ public TransferPair getTransferPair(); + + public TransferPair makeTransferPair(ValueVector to); public TransferPair getTransferPair(FieldReference ref); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/main/resources/drill-module.conf ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/resources/drill-module.conf b/exec/java-exec/src/main/resources/drill-module.conf index 090fe9a..81e6135 100644 --- a/exec/java-exec/src/main/resources/drill-module.conf +++ b/exec/java-exec/src/main/resources/drill-module.conf @@ -84,5 +84,17 @@ drill.exec: { } }, cache.hazel.subnets: ["*.*.*.*"], - sort.purge.threshold : 100 + sort: { + purge.threshold : 100, + external: { + batch.size : 4000, + spill: { + batch.size : 4000, + group.size : 100, + threshold : 200, + directories : [ "/tmp/drill/spill" ], + fs : "file:///" + } + } + } } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/test/java/org/apache/drill/TestExampleQueries.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/TestExampleQueries.java b/exec/java-exec/src/test/java/org/apache/drill/TestExampleQueries.java index 7895897..7199c65 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/TestExampleQueries.java +++ b/exec/java-exec/src/test/java/org/apache/drill/TestExampleQueries.java @@ -26,6 +26,7 @@ import org.junit.rules.TestRule; public class TestExampleQueries extends BaseTestQuery{ static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(TestExampleQueries.class); + @Rule public TestRule TIMEOUT = TestTools.getTimeoutRule(20000); @Test public void testSelectWithLimit() throws Exception{ http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/xsort/TestSimpleExternalSort.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/xsort/TestSimpleExternalSort.java b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/xsort/TestSimpleExternalSort.java new file mode 100644 index 0000000..8b3d36e --- /dev/null +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/xsort/TestSimpleExternalSort.java @@ -0,0 +1,146 @@ +/** + * 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.drill.exec.physical.impl.xsort; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.apache.drill.common.config.DrillConfig; +import org.apache.drill.common.expression.ExpressionPosition; +import org.apache.drill.common.expression.SchemaPath; +import org.apache.drill.common.util.FileUtils; +import org.apache.drill.exec.client.DrillClient; +import org.apache.drill.exec.pop.PopUnitTestBase; +import org.apache.drill.exec.proto.UserProtos; +import org.apache.drill.exec.record.RecordBatchLoader; +import org.apache.drill.exec.rpc.user.QueryResultBatch; +import org.apache.drill.exec.server.Drillbit; +import org.apache.drill.exec.server.RemoteServiceSet; +import org.apache.drill.exec.vector.BigIntVector; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class TestSimpleExternalSort extends PopUnitTestBase { + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(TestSimpleExternalSort.class); + DrillConfig c = DrillConfig.create(); + + + @Test + public void sortOneKeyDescendingMergeSort() throws Throwable{ + RemoteServiceSet serviceSet = RemoteServiceSet.getLocalServiceSet(); + + try(Drillbit bit1 = new Drillbit(CONFIG, serviceSet); + Drillbit bit2 = new Drillbit(CONFIG, serviceSet); + DrillClient client = new DrillClient(CONFIG, serviceSet.getCoordinator());) { + + bit1.run(); + bit2.run(); + client.connect(); + List<QueryResultBatch> results = client.runQuery(UserProtos.QueryType.PHYSICAL, + Files.toString(FileUtils.getResourceAsFile("/xsort/one_key_sort_descending.json"), + Charsets.UTF_8)); + int count = 0; + for(QueryResultBatch b : results) { + if (b.getHeader().getRowCount() != 0) + count += b.getHeader().getRowCount(); + } + assertEquals(1000000, count); + + long previousBigInt = Long.MAX_VALUE; + + int recordCount = 0; + int batchCount = 0; + + for (QueryResultBatch b : results) { + if (b.getHeader().getRowCount() == 0) break; + batchCount++; + RecordBatchLoader loader = new RecordBatchLoader(bit1.getContext().getAllocator()); + loader.load(b.getHeader().getDef(),b.getData()); + BigIntVector c1 = (BigIntVector) loader.getValueAccessorById(loader.getValueVectorId(new SchemaPath("blue", ExpressionPosition.UNKNOWN)).getFieldId(), BigIntVector.class).getValueVector(); + + + BigIntVector.Accessor a1 = c1.getAccessor(); +// IntVector.Accessor a2 = c2.getAccessor(); + + for(int i =0; i < c1.getAccessor().getValueCount(); i++){ + recordCount++; + assertTrue(String.format("%d > %d", previousBigInt, a1.get(i)), previousBigInt >= a1.get(i)); + previousBigInt = a1.get(i); + } + } + + System.out.println(String.format("Sorted %,d records in %d batches.", recordCount, batchCount)); + + } + } + + @Test + public void sortOneKeyDescendingExternalSort() throws Throwable{ + RemoteServiceSet serviceSet = RemoteServiceSet.getLocalServiceSet(); + + DrillConfig config = DrillConfig.create("drill-external-sort.conf"); + + try(Drillbit bit1 = new Drillbit(config, serviceSet); + Drillbit bit2 = new Drillbit(config, serviceSet); + DrillClient client = new DrillClient(config, serviceSet.getCoordinator());) { + + bit1.run(); + bit2.run(); + client.connect(); + List<QueryResultBatch> results = client.runQuery(UserProtos.QueryType.PHYSICAL, + Files.toString(FileUtils.getResourceAsFile("/xsort/one_key_sort_descending.json"), + Charsets.UTF_8)); + int count = 0; + for(QueryResultBatch b : results) { + if (b.getHeader().getRowCount() != 0) + count += b.getHeader().getRowCount(); + } + assertEquals(1000000, count); + + long previousBigInt = Long.MAX_VALUE; + + int recordCount = 0; + int batchCount = 0; + + for (QueryResultBatch b : results) { + if (b.getHeader().getRowCount() == 0) break; + batchCount++; + RecordBatchLoader loader = new RecordBatchLoader(bit1.getContext().getAllocator()); + loader.load(b.getHeader().getDef(),b.getData()); + BigIntVector c1 = (BigIntVector) loader.getValueAccessorById(loader.getValueVectorId(new SchemaPath("blue", ExpressionPosition.UNKNOWN)).getFieldId(), BigIntVector.class).getValueVector(); + + + BigIntVector.Accessor a1 = c1.getAccessor(); +// IntVector.Accessor a2 = c2.getAccessor(); + + for(int i =0; i < c1.getAccessor().getValueCount(); i++){ + recordCount++; + assertTrue(String.format("%d < %d", previousBigInt, a1.get(i)), previousBigInt >= a1.get(i)); + previousBigInt = a1.get(i); + } + } + + System.out.println(String.format("Sorted %,d records in %d batches.", recordCount, batchCount)); + + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/test/resources/drill-external-sort.conf ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/resources/drill-external-sort.conf b/exec/java-exec/src/test/resources/drill-external-sort.conf new file mode 100644 index 0000000..52e4303 --- /dev/null +++ b/exec/java-exec/src/test/resources/drill-external-sort.conf @@ -0,0 +1,21 @@ +// This file tells Drill to consider this module when class path scanning. +// This file can also include any supplementary configuration information. +// This file is in HOCON format, see https://github.com/typesafehub/config/blob/master/HOCON.md for more information. + +drill.logical.function.packages += "org.apache.drill.exec.expr.fn.impl" + +drill.exec: { +sort: { + purge.threshold : 100, + external: { + batch.size : 4000, + spill: { + batch.size : 1000, + group.size : 4, + threshold : 4, + directories : [ "/tmp/drill/spill" ], + fs : "file:///" + } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/test/resources/sort/one_key_sort.json ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/resources/sort/one_key_sort.json b/exec/java-exec/src/test/resources/sort/one_key_sort.json index baabcb3..6e5d617 100644 --- a/exec/java-exec/src/test/resources/sort/one_key_sort.json +++ b/exec/java-exec/src/test/resources/sort/one_key_sort.json @@ -12,11 +12,11 @@ pop:"mock-sub-scan", url: "http://apache.org", entries:[ - {records: 1000000, types: [ + {records: 10000000, types: [ {name: "blue", type: "INT", mode: "REQUIRED"}, {name: "green", type: "INT", mode: "REQUIRED"} ]}, - {records: 1000000, types: [ + {records: 10000000, types: [ {name: "blue", type: "INT", mode: "REQUIRED"}, {name: "green", type: "INT", mode: "REQUIRED"} ]} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aee79720/exec/java-exec/src/test/resources/xsort/one_key_sort_descending.json ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/resources/xsort/one_key_sort_descending.json b/exec/java-exec/src/test/resources/xsort/one_key_sort_descending.json new file mode 100644 index 0000000..efb887b --- /dev/null +++ b/exec/java-exec/src/test/resources/xsort/one_key_sort_descending.json @@ -0,0 +1,48 @@ +{ + head:{ + type:"APACHE_DRILL_PHYSICAL", + version:"1", + generator:{ + type:"manual" + } + }, + graph:[ + { + @id:1, + pop:"mock-scan", + url: "http://apache.org", + entries:[ + {records: 1000000, types: [ + {name: "blue", type: "INT", mode: "REQUIRED"}, + {name: "green", type: "INT", mode: "REQUIRED"} + ]} + ] + }, + { + @id: 2, + pop: "project", + child: 1, + exprs: [ + { ref: "blue", expr: "randomBigInt(100000)" } + ] + }, + { + @id:3, + child: 2, + pop:"external-sort", + orderings: [ + {expr: "blue", order : "DESC"} + ] + }, + { + @id:4, + child: 3, + pop:"selection-vector-remover" + }, + { + @id: 5, + child: 4, + pop: "screen" + } + ] +} \ No newline at end of file
