[ https://issues.apache.org/jira/browse/DRILL-6126?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16385718#comment-16385718 ]
ASF GitHub Bot commented on DRILL-6126: --------------------------------------- Github user paul-rogers commented on a diff in the pull request: https://github.com/apache/drill/pull/1125#discussion_r172105104 --- Diff: exec/java-exec/src/main/java/org/apache/drill/exec/record/RecordBatchSizer.java --- @@ -76,110 +82,327 @@ * greater than (but unlikely) same as the row count. */ - public final int valueCount; + private final int valueCount; /** - * Total number of elements for a repeated type, or 1 if this is - * a non-repeated type. That is, a batch of 100 rows may have an - * array with 10 elements per row. In this case, the element count - * is 1000. + * Total number of elements for a repeated type, or same as + * valueCount if this is a non-repeated type. That is, a batch + * of 100 rows may have an array with 10 elements per row. + * In this case, the element count is 1000. */ - public final int elementCount; + private int elementCount; /** - * Size of the top level value vector. For map and repeated list, - * this is just size of offset vector. + * The estimated, average number of elements per parent value. + * Always 1 for a non-repeated type. For a repeated type, + * this is the average entries per array (per repeated element). */ - public int dataSize; + + private float estElementCountPerArray; /** - * Total size of the column includes the sum total of memory for all - * value vectors representing the column. + * Indicates if it is variable width column. + * For map columns, this is true if any of the children is variable + * width column. */ - public int netSize; + + private boolean isVariableWidth; /** - * The estimated, average number of elements per parent value. - * Always 1 for a non-repeated type. For a repeated type, - * this is the average entries per array (per repeated element). + * Indicates if cardinality is repeated(top level only). + */ + + private boolean isRepeated; + + /** + * Indicates if cardinality is optional i.e. nullable(top level only). + */ + private boolean isOptional; + + /** + * Child columns if this is a map column. + */ + private Map<String, ColumnSize> children = CaseInsensitiveMap.newHashMap(); + + /** + * std pure data size per entry from Drill metadata, based on type. + * Does not include metadata vector overhead we add for cardinality, + * variable length etc. + * For variable-width columns, we use 50 as std size for entry width. + * For repeated column, we assume repetition of 10. + */ + public int getStdDataSizePerEntry() { + int stdDataSize; + + try { + stdDataSize = TypeHelper.getSize(metadata.getType()); + + // For variable width, typeHelper includes offset vector width. Adjust for that. + if (isVariableWidth) { + stdDataSize -= OFFSET_VECTOR_WIDTH; + } + + if (isRepeated) { + stdDataSize = stdDataSize * STD_REPETITION_FACTOR; + } + } catch (Exception e) { + // For unsupported types, just set stdSize to 0. + // Map, Union, List etc. + stdDataSize = 0; + } + + // Add sizes of children. + for (ColumnSize columnSize : children.values()) { + stdDataSize += columnSize.getStdDataSizePerEntry(); + } + + if (isRepeatedList()) { + stdDataSize = stdDataSize * STD_REPETITION_FACTOR; + } + + return stdDataSize; + } + + /** + * std net size per entry taking into account additional metadata vectors + * we add on top for variable length, cardinality etc. + * For variable-width columns, we use 50 as std data size for entry width. + * For repeated column, we assume repetition of 10. + */ + public int getStdNetSizePerEntry() { + int stdNetSize; + try { + stdNetSize = TypeHelper.getSize(metadata.getType()); + } catch (Exception e) { + stdNetSize = 0; + } + + if (isOptional) { + stdNetSize += BIT_VECTOR_WIDTH; + } + + if (isRepeated) { + stdNetSize = (stdNetSize * STD_REPETITION_FACTOR) + OFFSET_VECTOR_WIDTH; + } + + for (ColumnSize columnSize : children.values()) { + stdNetSize += columnSize.getStdNetSizePerEntry(); + } + + if (isRepeatedList()) { + stdNetSize = (stdNetSize * STD_REPETITION_FACTOR) + OFFSET_VECTOR_WIDTH; + } + + return stdNetSize; + } + + /** + * This is the average actual per entry data size in bytes. Does not + * include any overhead of metadata vectors. + * For repeated columns, it is average for the repeated array, not + * individual entry in the array. + */ + public int getDataSizePerEntry() { + return safeDivide(getTotalDataSize(), getValueCount()); + } + + /** + * This is the average per entry size of just pure data plus + * overhead of additional vectors we add on top like bits vector, + * offset vector etc. This + * size is larger than the actual data size since this size includes per- + * column overhead for additional vectors we add for + * cardinality, variable length etc. + */ + public int getNetSizePerEntry() { + return safeDivide(getTotalNetSize(), getValueCount()); + } + + /** + * This is the total data size for the column, including children for map + * columns. Does not include any overhead of metadata vectors. + */ + public int getTotalDataSize() { + int dataSize = this.totalDataSize; + for (ColumnSize columnSize : children.values()) { + dataSize += columnSize.getTotalDataSize(); + } + return dataSize; + } + + /** + * This is the total net size for the column, including children for map + * columns. Includes overhead of metadata vectors. */ + public int getTotalNetSize() { + return this.totalNetSize; + } + + public int getValueCount() { + return valueCount; + } - public final float estElementCountPerArray; - public final boolean isVariableWidth; + public int getElementCount() { + return elementCount; + } + + public float getEstElementCountPerArray() { + return estElementCountPerArray; + } - public Map<String, ColumnSize> children = CaseInsensitiveMap.newHashMap(); + public boolean isVariableWidth() { + return isVariableWidth; + } public Map<String, ColumnSize> getChildren() { return children; } + public boolean isComplex() { + if (metadata.getType().getMinorType() == MinorType.MAP || + metadata.getType().getMinorType() == MinorType.UNION || + metadata.getType().getMinorType() == MinorType.LIST) { + return true; + } + return false; + } + + public boolean isRepeatedList() { + if (metadata.getType().getMinorType() == MinorType.LIST && + metadata.getDataMode() == DataMode.REPEATED) { + return true; + } + return false; + } + + /** + * This is the average per entry width, used for vector allocation. + */ + public int getEntryWidth() { + int width = 0; + if (isVariableWidth) { + width = getNetSizePerEntry() - OFFSET_VECTOR_WIDTH; + + // Subtract out the bits (is-set) vector width + if (metadata.getDataMode() == DataMode.OPTIONAL) { + width -= BIT_VECTOR_WIDTH; + } + } + + return (safeDivide(width, estElementCountPerArray)); + } + public ColumnSize(ValueVector v, String prefix) { this.prefix = prefix; valueCount = v.getAccessor().getValueCount(); metadata = v.getField(); - isVariableWidth = v instanceof VariableWidthVector; - - // The amount of memory consumed by the payload: the actual - // data stored in the vectors. - - if (v.getField().getDataMode() == DataMode.REPEATED) { - elementCount = buildRepeated(v); - estElementCountPerArray = valueCount == 0 ? 0 : elementCount * 1.0f / valueCount; - } else { - elementCount = 1; - estElementCountPerArray = 1; + isVariableWidth = (v instanceof VariableWidthVector || v instanceof RepeatedVariableWidthVectorLike); + elementCount = valueCount; + estElementCountPerArray = 1; + totalNetSize = v.getPayloadByteCount(valueCount); + + // Special case. For union and list vectors, it is very complex + // to figure out raw data size. Make it same as net size. + if (metadata.getType().getMinorType() == MinorType.UNION || + (metadata.getType().getMinorType() == MinorType.LIST && v.getField().getDataMode() != DataMode.REPEATED)) { + totalDataSize = totalNetSize; } - switch (metadata.getType().getMinorType()) { - case LIST: - buildList(v); - break; - case MAP: - case UNION: - // No standard size for Union type - dataSize = v.getPayloadByteCount(valueCount); - break; - default: - dataSize = v.getPayloadByteCount(valueCount); - try { - stdSize = TypeHelper.getSize(metadata.getType()) * elementCount; - } catch (Exception e) { - // For unsupported types, just set stdSize to 0. - stdSize = 0; - } + + switch(v.getField().getDataMode()) { --- End diff -- Once code gets this complex, it may be time to create subclasses for the three modes. Plus subclasses for the categories of types (variable-width, map, etc.) The column size would be a composition of the type size class plus a cardinality size class. Maybe overkill for the current round of changes, but something to keep in mind if this code continues to grow in complexity. > Allocate memory for value vectors upfront in flatten operator > ------------------------------------------------------------- > > Key: DRILL-6126 > URL: https://issues.apache.org/jira/browse/DRILL-6126 > Project: Apache Drill > Issue Type: Improvement > Reporter: Padma Penumarthy > Assignee: Padma Penumarthy > Priority: Critical > Fix For: 1.12.0 > > > With recent changes to control batch size for flatten operator, we figure out > row count in the output batch based on memory. Since we know how many rows we > are going to include in the batch, we can also allocate the memory needed > upfront instead of starting with initial value (4096) and doubling, copying > every time we need more. -- This message was sent by Atlassian JIRA (v7.6.3#76005)