You are viewing a plain text version of this content. The canonical link for it is here.
Posted to reviews@spark.apache.org by JoshRosen <gi...@git.apache.org> on 2015/04/27 20:37:00 UTC

[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

GitHub user JoshRosen opened a pull request:

    https://github.com/apache/spark/pull/5725

    [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use managed memory for aggregations

    This patch adds managed-memory-based aggregation to Spark SQL / DataFrames. Instead of working with Java objects, this new aggregation path uses `sun.misc.Unsafe` to manipulate raw memory.  This reduces the memory footprint for aggregations, resulting in fewer spills, OutOfMemoryErrors, and garbage collection pauses.  As a result, this allows for higher memory utilization.  It can also result in better cache locality since objects will be stored closer together in memory.
    
    This feature can be eanbled by setting `spark.sql.unsafe.enabled=true`.  For now, this feature is only supported when codegen is enabled and only supports aggregations for which the grouping columns are primitive numeric types or strings and aggregated values are numeric.
    
    ### Managing memory with sun.misc.Unsafe
    
    This patch supports both on- and off-heap managed memory.
    
    - In on-heap mode, memory addresses are identified by the combination of a base Object and an offset within that object.
    - In off-heap mode, memory is addressed directly with 64-bit long addresses.
    
    To support both modes, functions that manipulate memory accept both `baseObject` and `baseOffset` fields.  In off-heap mode, we simply pass `null` as `baseObject`.
    
    We allocate memory in large chunks, so memory fragmentation and allocation speed are not significant bottlenecks.
    
    By default, we use on-heap mode.  To enable off-heap mode, set `spark.sql.unsafe.offHeap=true`.
    
    ### Compact tuple format
    
    This patch introduces `UnsafeRow`, a compact row layout.  In this format, each tuple has three parts: a null bit set, fixed length values, and variable-length values:
    
    ![image](https://cloud.githubusercontent.com/assets/50748/7328538/2fdb65ce-ea8b-11e4-9743-6c0f02bb7d1f.png)
    
    - Rows are always 8-byte word aligned (so their sizes will always be a multiple of 8 bytes)
    - The bit set is used for null tracking:
    	- Position _i_ is set if and only if field _i_ is null
    	- The bit set is aligned to an 8-byte word boundary.
    - Every field appears as an 8-byte word in the fixed-length values part:
    	- If a field is null, we zero out the values.
    	- If a field is variable-length, the word stores a relative offset (w.r.t. the base of the tuple) that points to the beginning of the field's data in the variable-length part.
    - Each variable-length data type can have its own encoding:
    	- For strings, the first word stores the length of the string and is followed by UTF-8 encoded bytes.  If necessary, the end of the string is padded with empty bytes in order to ensure word-alignment.
    
    For example, a tuple that consists 3 fields of type (int, string, string), with value (null, “data”, “bricks”) would look like this:
    
    ![image](https://cloud.githubusercontent.com/assets/50748/7328526/1e21959c-ea8b-11e4-9a28-a4350fe4a7b5.png)
    
    This format allows us to compare tuples for equality by directly comparing their raw bytes.  This also enables fast hashing of tuples.
    
    ### Hash map for performing aggregations
    
    This patch introduces `UnsafeFixedWidthAggregationMap`, a hash map for performing aggregations where the aggregation result columns are fixed-with.  This map's keys and values are `Row` objects. `UnsafeFixedWidthAggregationMap` is implemented on top of `BytesToBytesMap`, an append-only map which supports byte-array keys and values.
    
    `BytesToBytesMap` stores pointers to key and value tuples.  For each record with a new key, we copy the key and create the aggregation value buffer for that key and put them in a buffer. The hash table then simply stores pointers to the key and value. For each record with an existing key, we simply run the aggregation function to update the values in place.
    
    This map is implemented using open hashing with triangular sequence probing.  Each entry stores two words in a long array: the first word stores the address of the key and the second word stores the relative offset from the key tuple to the value tuple, as well as the key's 32-bit hashcode.  By storing the full hashcode, we reduce the number of equality checks that need to be performed to handle position collisions ()since the chance of hashcode collision is much lower than position collision).
    
    `UnsafeFixedWidthAggregationMap` allows regular Spark SQL `Row` objects to be used when probing the map.  Internally, it encodes these rows into `UnsafeRow` format using `UnsafeRowConverter`.  This conversion has a small overhead that can be eliminated in the future once we use UnsafeRows in other operators.

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/JoshRosen/spark unsafe

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/spark/pull/5725.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #5725
    
----
commit 480a74a12b9a3e3d71c1b65dcc41c9111ed33958
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-17T22:28:50Z

    Initial import of code from Databricks unsafe utils repo.

commit ab68e081eef12333ff6c475cd70759ab7c6aeb74
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-18T00:38:51Z

    Begin merging the UTF8String implementations.

commit f03e9c17e2458c1f081196c27ac44abe70d5be36
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-18T04:58:58Z

    Play around with Unsafe implementations of more string methods.

commit 5d55cef9edcedae114d095ab656512fd4b3946ac
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-18T05:22:48Z

    Add skeleton for Row implementation.

commit 8a8f9df5af0adac1ceb078443c6dade3a76d8fce
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-18T05:59:02Z

    Add skeleton for GeneratedAggregate integration.
    
    This typechecks properly and sketches how I'm intending to use row pointers
    and the hashmap. This has been a useful exercise for figuring out whether my
    interfaces will be sufficient.

commit 1ff814de9f7c4f1716e09d75f06fa261822784ee
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-18T06:11:35Z

    Add reminder to free memory on iterator completion

commit 53ba9b79e12a58f5c4ee217e434fbc20195ffc62
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-19T05:11:37Z

    Start prototyping Java Row -> UnsafeRow converters

commit fc4c3a8aa5b345526298379124530b6c2793d9e5
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-19T05:26:51Z

    Sketch how the converters will be used in UnsafeGeneratedAggregate

commit 1a483c5a7303d4267e5a2adb10fa23c672224361
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-19T07:50:07Z

    First version that passes some aggregation tests:
    
    I commented out a number of tests where we do not support the required
    data types; this is only a short-term hack until I extend the planner
    to understand when UnsafeGeneratedAggregate can be used.

commit 079f1bf3b8d0b72eae5882d1c1ae69db6d21c7cd
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-19T19:54:10Z

    Some clarification of the BytesToBytesMap.lookup() / set() contract.

commit f764d1324ee0aa327217c3bf98868f06c0ae7fbf
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-19T20:22:15Z

    Simplify address + length calculation in Location.

commit c754ae142933a901738be00ae865b96f6ca47f1f
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-19T22:56:01Z

    Now that the store*() contract has been stregthened, we can remove an extra lookup

commit ae39694e722753da288c66455267a3acfca09187
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-19T23:47:34Z

    Add finalizer as "cleanup method of last resort"

commit c7f0b563168048c0ec046a45d3cad6b81491d4b1
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-20T00:06:37Z

    Reuse UnsafeRow pointer in UnsafeRowConverter

commit 62ab054db492fd77289150edd3705539f5848a39
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-20T00:39:33Z

    Optimize for fact that get() is only called on String columns.

commit c55bf668efe9494caca1f7952c37b34035341cea
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-20T00:53:49Z

    Free buffer once iterator has been fully consumed.

commit 738fa3392375759078ab6a8c677af712257875b9
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-20T22:09:51Z

    Add feature flag to guard UnsafeGeneratedAggregate

commit c1b3813bcaa6be5fde7ac18bceaaa307e2203596
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-20T23:53:49Z

    Fix bug in UnsafeMemoryAllocator.free():
    
    The `if` check here was backwards, which prevented any memory from
    being freed.

commit 7df600872f1a8e61b4544464f412b940501fb487
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-21T00:32:21Z

    Optimizations related to zeroing out memory:
    
    - Do not zero out all allocated memory; the zeroing isn't free and in many
      cases it isn't necessary.
    - There are some cases where we do want to clear the memory, such as in BitSet.
    
      It shouldn't be the BitSet object's responsibility to zero out the memory
      block passed to it (since maybe we're passing some memory created by someone
      else and want to interpret it as a bitset). To make the caller's life easier,
      though, I added a MemoryBlock.zero() method for clearing the block.
    
    - In UnsafeGeneratedAggregate, use Arrays.fill to clear the re-used temporary
      row buffer, since this is likely to be much faster than Unsafe.setMemory;
      see http://psy-lob-saw.blogspot.com/2015/04/on-arraysfill-intrinsics-superword-and.html
      for more details.

commit 58ac3938e892a092dafba80b870d21e23698f111
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-21T00:36:58Z

    Use UNSAFE allocator in GeneratedAggregate (TODO: make this configurable)

commit d2bb986fce7fedaccd7875452126481a068ebace
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-22T03:24:03Z

    Update to implement new Row methods added upstream

commit b3eaccde0f00453d01be551cb7819c3a92a4f65c
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-22T04:21:20Z

    Extract aggregation map into its own class.
    
    This makes the code much easier to understand and
    will allow me to implement unsafe versions of both
    GeneratedAggregate and the regular Aggregate operator.

commit bade9665d165a75bd7915b9a9a6cb196a77e73e8
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-22T04:23:34Z

    Comment update (bumping to refresh GitHub cache...)

commit d85eeff90040a6c4de3c7607cf75d9e7b23f04bf
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-22T06:05:47Z

    Add basic sanity test for UnsafeFixedWidthAggregationMap

commit 1f4b7166afeaef2bf44fc6302499f5264c0df596
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-22T21:40:59Z

    Merge Unsafe code into the regular GeneratedAggregate, guarded by a
    configuration flag; integrate planner support and re-enable all tests.

commit 92d5a06b181b56baed23fea22f58cb82d8f83d30
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-23T19:10:11Z

    Address a number of minor code review comments.

commit 628f9366bac4687dd393f336d7d23eea1e17364b
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-23T20:25:32Z

    Use ints intead of longs for indexing.

commit 23a440ac3636012595359d2d098c6da27e07fa5b
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-23T20:29:06Z

    Bump up default hash map size

commit 765243d387667ca3470259769ad57f71162e09e2
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-23T22:15:37Z

    Enable optional performance metrics for hash map.

commit b26f1d374672b0ff5657fe89463095e90d246269
Author: Josh Rosen <jo...@databricks.com>
Date:   2015-04-23T23:49:53Z

    Fix bug in murmur hash implementation.

----


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29221599
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java ---
    @@ -0,0 +1,552 @@
    +/*
    + * 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.spark.unsafe.map;
    +
    +import java.lang.Override;
    +import java.lang.UnsupportedOperationException;
    +import java.util.Iterator;
    +import java.util.LinkedList;
    +import java.util.List;
    +
    +import org.apache.spark.unsafe.*;
    +import org.apache.spark.unsafe.array.ByteArrayMethods;
    +import org.apache.spark.unsafe.array.LongArray;
    +import org.apache.spark.unsafe.bitset.BitSet;
    +import org.apache.spark.unsafe.hash.Murmur3_x86_32;
    +import org.apache.spark.unsafe.memory.*;
    +
    +/**
    + * An append-only hash map where keys and values are contiguous regions of bytes.
    + * <p>
    + * This is backed by a power-of-2-sized hash table, using quadratic probing with triangular numbers,
    + * which is guaranteed to exhaust the space.
    + * <p>
    + * Note that even though we use long for indexing, the map can support up to 2^31 keys because
    + * we use 32 bit MurmurHash. In either case, if the key cardinality is so high, you should probably
    + * be using sorting instead of hashing for better cache locality.
    + * <p>
    + * This class is not thread safe.
    + */
    +public final class BytesToBytesMap {
    +
    +  private static final Murmur3_x86_32 HASHER = new Murmur3_x86_32(0);
    +
    +  private static final HashMapGrowthStrategy growthStrategy = HashMapGrowthStrategy.DOUBLING;
    +
    +  private final MemoryManager memoryManager;
    +
    +  /**
    +   * A linked list for tracking all allocated data pages so that we can free all of our memory.
    +   */
    +  private final List<MemoryBlock> dataPages = new LinkedList<MemoryBlock>();
    +
    +  /**
    +   * The data page that will be used to store keys and values for new hashtable entries. When this
    +   * page becomes full, a new page will be allocated and this pointer will change to point to that
    +   * new page.
    +   */
    +  private MemoryBlock currentDataPage = null;
    +
    +  /**
    +   * Offset into `currentDataPage` that points to the location where new data can be inserted into
    +   * the page.
    +   */
    +  private long pageCursor = 0;
    +
    +  /**
    +   * The size of the data pages that hold key and value data. Map entries cannot span multiple
    +   * pages, so this limits the maximum entry size.
    +   */
    +  private static final long PAGE_SIZE_BYTES = 1L << 26; // 64 megabytes
    +
    +  // This choice of page table size and page size means that we can address up to 500 gigabytes
    +  // of memory.
    +
    +  /**
    +   * A single array to store the key and value.
    +   *
    +   * Position {@code 2 * i} in the array is used to track a pointer to the key at index {@code i},
    +   * while position {@code 2 * i + 1} in the array holds key's full 32-bit hashcode.
    +   */
    +  private LongArray longArray;
    +  // TODO: we're wasting 32 bits of space here; we can probably store fewer bits of the hashcode
    +  // and exploit word-alignment to use fewer bits to hold the address.  This might let us store
    +  // only one long per map entry, increasing the chance that this array will fit in cache at the
    +  // expense of maybe performing more lookups if we have hash collisions.  Say that we stored only
    +  // 27 bits of the hashcode and 37 bits of the address.  37 bits is enough to address 1 terabyte
    +  // of RAM given word-alignment.  If we use 13 bits of this for our page table, that gives us a
    +  // maximum page size of 2^24 * 8 = ~134 megabytes per page. This change will require us to store
    +  // full base addresses in the page table for off-heap mode so that we can reconstruct the full
    +  // absolute memory addresses.
    +
    +  /**
    +   * A {@link BitSet} used to track location of the map where the key is set.
    +   * Size of the bitset should be half of the size of the long array.
    +   */
    +  private BitSet bitset;
    +
    +  private final double loadFactor;
    +
    +  /**
    +   * Number of keys defined in the map.
    +   */
    +  private int size;
    +
    +  /**
    +   * The map will be expanded once the number of keys exceeds this threshold.
    +   */
    +  private int growthThreshold;
    +
    +  /**
    +   * Mask for truncating hashcodes so that they do not exceed the long array's size.
    --- End diff --
    
    call out explicitly the strength reduction here. Essentially a mod operation, but done using a bit mask since this is power-of-2 sized hash map.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29218943
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeRow.java ---
    @@ -0,0 +1,428 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import scala.collection.Map;
    +import scala.collection.Seq;
    +import scala.collection.mutable.ArraySeq;
    +
    +import javax.annotation.Nullable;
    +import java.math.BigDecimal;
    +import java.sql.Date;
    +import java.util.*;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.DataType;
    +import static org.apache.spark.sql.types.DataTypes.*;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.sql.types.UTF8String;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.bitset.BitSetMethods;
    +
    +/**
    + * An Unsafe implementation of Row which is backed by raw memory instead of Java objects.
    + *
    + * Each tuple has three parts: [null bit set] [values] [variable length portion]
    + *
    + * The bit set is used for null tracking and is aligned to 8-byte word boundaries.  It stores
    + * one bit per field.
    + *
    + * In the `values` region, we store one 8-byte word per field. For fields that hold fixed-length
    + * primitive types, such as long, double, or int, we store the value directly in the word. For
    + * fields with non-primitive or variable-length values, we store a relative offset (w.r.t. the
    + * base address of the row) that points to the beginning of the variable-length field.
    + *
    + * Instances of `UnsafeRow` act as pointers to row data stored in this format, similar to how
    + * `Writable` objects work in Hadoop.
    + */
    +public final class UnsafeRow implements MutableRow {
    +
    +  private Object baseObject;
    +  private long baseOffset;
    +  /** The number of fields in this row, used for calculating the bitset width (and in assertions) */
    +  private int numFields;
    +  /** The width of the null tracking bit set, in bytes */
    +  private int bitSetWidthInBytes;
    +  /**
    +   * This optional schema is required if you want to call generic get() and set() methods on
    +   * this UnsafeRow, but is optional if callers will only use type-specific getTYPE() and setTYPE()
    +   * methods.
    +   */
    +  @Nullable
    +  private StructType schema;
    +
    +  private long getFieldOffset(int ordinal) {
    +   return baseOffset + bitSetWidthInBytes + ordinal * 8L;
    +  }
    +
    +  public static int calculateBitSetWidthInBytes(int numFields) {
    +    return ((numFields / 64) + (numFields % 64 == 0 ? 0 : 1)) * 8;
    +  }
    +
    +  /**
    +   * Field types that can be updated in place in UnsafeRows (e.g. we support set() for these types)
    +   */
    +  public static final Set<DataType> settableFieldTypes;
    +
    +  /**
    +   * Fields types can be read(but not set (e.g. set() will throw UnsupportedOperationException).
    +   */
    +  public static final Set<DataType> readableFieldTypes;
    +
    +  static {
    +    settableFieldTypes = Collections.unmodifiableSet(
    +      new HashSet<DataType>(
    +        Arrays.asList(new DataType[] {
    --- End diff --
    
    date and timestamp should also be supported?
    
    we can do it in a future PR though -- maybe create jira tickets under https://issues.apache.org/jira/browse/SPARK-7075


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29287015
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryManager.java ---
    @@ -0,0 +1,176 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.BitSet;
    +
    +/**
    + * Manages the lifecycle of data pages exchanged between operators.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    --- End diff --
    
    Done.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29303644
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -41,13 +42,15 @@ case class AggregateEvaluation(
      * @param groupingExpressions expressions that are evaluated to determine grouping.
      * @param aggregateExpressions expressions that are computed for each group.
      * @param child the input data source.
    + * @param unsafeEnabled whether to allow Unsafe-based aggregation buffers to be used.
      */
     @DeveloperApi
     case class GeneratedAggregate(
    --- End diff --
    
    Agreed.  I'd like to avoid duplication of the code generation logic, though.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97246248
  
     Merged build triggered.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29221149
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryBlock.java ---
    @@ -0,0 +1,74 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import javax.annotation.Nullable;
    +
    +import org.apache.spark.unsafe.PlatformDependent;
    +
    +/**
    + * A consecutive block of memory, starting at a {@link MemoryLocation} with a fixed size.
    + */
    +public class MemoryBlock extends MemoryLocation {
    +
    +  private final long length;
    +
    +  /**
    +   * Optional page number; used when this MemoryBlock represents a page allocated by a
    +   * MemoryManager. This is package-private and is modified by MemoryManager.
    +   */
    +  int pageNumber = -1;
    +
    +  public int getPageNumber() {
    +    return pageNumber;
    +  }
    +
    +  MemoryBlock(@Nullable Object obj, long offset, long length) {
    +    super(obj, offset);
    +    this.length = length;
    +  }
    +
    +  /**
    +   * Returns the size of the memory block.
    +   */
    +  public long size() {
    +    return length;
    +  }
    +
    +  /**
    +   * Clear the contents of this memory block.  Returns `this` to facilitate chaining.
    +   */
    +  public MemoryBlock zero() {
    +    PlatformDependent.UNSAFE.setMemory(obj, offset, length, (byte) 0);
    +    return this;
    +  }
    +
    +  /**
    +   * Creates a memory block pointing to the memory used by the byte array.
    +   */
    +  public static MemoryBlock fromByteArray(final byte[] array) {
    --- End diff --
    
    can we remove this since it is not used?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29221064
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -265,7 +284,49 @@ case class GeneratedAggregate(
     
             val resultProjection = resultProjectionBuilder()
             Iterator(resultProjection(buffer))
    +      } else if (unsafeEnabled && schemaSupportsUnsafe) {
    +        log.info("Using Unsafe-based aggregator")
    +        val aggregationMap = new UnsafeFixedWidthAggregationMap(
    +          newAggregationBuffer(EmptyRow),
    +          aggregationBufferSchema,
    +          groupKeySchema,
    +          SparkEnv.get.unsafeMemoryManager,
    +          1024 * 16,
    --- End diff --
    
    use named argument for this


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96846436
  
      [Test build #31069 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31069/consoleFull) for   PR 5725 at commit [`0925847`](https://github.com/apache/spark/commit/092584701277394a704c7600c6a631326d7895c6).
     * This patch **passes all tests**.
     * This patch merges cleanly.
     * This patch adds the following public classes _(experimental)_:
      * `public final class UnsafeFixedWidthAggregationMap `
      * `  public static class MapEntry `
      * `public final class UnsafeRow implements MutableRow `
      * `class UnsafeRowConverter(fieldTypes: Array[DataType]) `
      * `public final class PlatformDependent `
      * `public class ByteArrayMethods `
      * `public final class LongArray `
      * `public final class BitSet `
      * `public final class BitSetMethods `
      * `public final class Murmur3_x86_32 `
      * `public final class BytesToBytesMap `
      * `  public final class Location `
      * `  class Doubling implements HashMapGrowthStrategy `
      * `public class HeapMemoryAllocator implements MemoryAllocator `
      * `public class MemoryBlock extends MemoryLocation `
      * `public class MemoryLocation `
      * `public class UnsafeMemoryAllocator implements MemoryAllocator `
    
     * This patch **adds the following new dependencies:**
       * `spark-unsafe_2.10-1.4.0-SNAPSHOT.jar`



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97311169
  
    Merged build started.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29221238
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryManager.java ---
    @@ -0,0 +1,176 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.BitSet;
    +
    +/**
    + * Manages the lifecycle of data pages exchanged between operators.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    + * numbers are used to index into a "page table" array inside of the MemoryManager in order to
    + * retrieve the base object.
    + */
    +public final class MemoryManager {
    +
    +  /**
    +   * The number of entries in the page table.
    +   */
    +  private static final int PAGE_TABLE_SIZE = (int) 1L << 13;
    --- End diff --
    
    why not just ```1 << 13``` ?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29267305
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java ---
    @@ -0,0 +1,552 @@
    +/*
    + * 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.spark.unsafe.map;
    +
    +import java.lang.Override;
    +import java.lang.UnsupportedOperationException;
    +import java.util.Iterator;
    +import java.util.LinkedList;
    +import java.util.List;
    +
    +import org.apache.spark.unsafe.*;
    +import org.apache.spark.unsafe.array.ByteArrayMethods;
    +import org.apache.spark.unsafe.array.LongArray;
    +import org.apache.spark.unsafe.bitset.BitSet;
    +import org.apache.spark.unsafe.hash.Murmur3_x86_32;
    +import org.apache.spark.unsafe.memory.*;
    +
    +/**
    + * An append-only hash map where keys and values are contiguous regions of bytes.
    + * <p>
    + * This is backed by a power-of-2-sized hash table, using quadratic probing with triangular numbers,
    + * which is guaranteed to exhaust the space.
    + * <p>
    + * Note that even though we use long for indexing, the map can support up to 2^31 keys because
    + * we use 32 bit MurmurHash. In either case, if the key cardinality is so high, you should probably
    + * be using sorting instead of hashing for better cache locality.
    + * <p>
    + * This class is not thread safe.
    + */
    +public final class BytesToBytesMap {
    +
    +  private static final Murmur3_x86_32 HASHER = new Murmur3_x86_32(0);
    +
    +  private static final HashMapGrowthStrategy growthStrategy = HashMapGrowthStrategy.DOUBLING;
    +
    +  private final MemoryManager memoryManager;
    +
    +  /**
    +   * A linked list for tracking all allocated data pages so that we can free all of our memory.
    +   */
    +  private final List<MemoryBlock> dataPages = new LinkedList<MemoryBlock>();
    +
    +  /**
    +   * The data page that will be used to store keys and values for new hashtable entries. When this
    +   * page becomes full, a new page will be allocated and this pointer will change to point to that
    +   * new page.
    +   */
    +  private MemoryBlock currentDataPage = null;
    +
    +  /**
    +   * Offset into `currentDataPage` that points to the location where new data can be inserted into
    +   * the page.
    +   */
    +  private long pageCursor = 0;
    +
    +  /**
    +   * The size of the data pages that hold key and value data. Map entries cannot span multiple
    +   * pages, so this limits the maximum entry size.
    +   */
    +  private static final long PAGE_SIZE_BYTES = 1L << 26; // 64 megabytes
    +
    +  // This choice of page table size and page size means that we can address up to 500 gigabytes
    +  // of memory.
    +
    +  /**
    +   * A single array to store the key and value.
    +   *
    +   * Position {@code 2 * i} in the array is used to track a pointer to the key at index {@code i},
    +   * while position {@code 2 * i + 1} in the array holds key's full 32-bit hashcode.
    +   */
    +  private LongArray longArray;
    +  // TODO: we're wasting 32 bits of space here; we can probably store fewer bits of the hashcode
    +  // and exploit word-alignment to use fewer bits to hold the address.  This might let us store
    +  // only one long per map entry, increasing the chance that this array will fit in cache at the
    +  // expense of maybe performing more lookups if we have hash collisions.  Say that we stored only
    +  // 27 bits of the hashcode and 37 bits of the address.  37 bits is enough to address 1 terabyte
    +  // of RAM given word-alignment.  If we use 13 bits of this for our page table, that gives us a
    +  // maximum page size of 2^24 * 8 = ~134 megabytes per page. This change will require us to store
    +  // full base addresses in the page table for off-heap mode so that we can reconstruct the full
    +  // absolute memory addresses.
    +
    +  /**
    +   * A {@link BitSet} used to track location of the map where the key is set.
    +   * Size of the bitset should be half of the size of the long array.
    +   */
    +  private BitSet bitset;
    +
    +  private final double loadFactor;
    +
    +  /**
    +   * Number of keys defined in the map.
    +   */
    +  private int size;
    +
    +  /**
    +   * The map will be expanded once the number of keys exceeds this threshold.
    +   */
    +  private int growthThreshold;
    +
    +  /**
    +   * Mask for truncating hashcodes so that they do not exceed the long array's size.
    +   */
    +  private int mask;
    +
    +  /**
    +   * Return value of {@link BytesToBytesMap#lookup(Object, long, int)}.
    +   */
    +  private final Location loc;
    +
    +  private final boolean enablePerfMetrics;
    +
    +  private long timeSpentResizingMs = 0;
    +
    +  private long numProbes = 0;
    +
    +  private long numKeyLookups = 0;
    +
    +  private long numHashCollisions = 0;
    +
    +  public BytesToBytesMap(
    +      MemoryManager memoryManager,
    +      int initialCapacity,
    +      double loadFactor,
    +      boolean enablePerfMetrics) {
    +    this.memoryManager = memoryManager;
    +    this.loadFactor = loadFactor;
    +    this.loc = new Location();
    +    this.enablePerfMetrics = enablePerfMetrics;
    +    allocate(initialCapacity);
    +  }
    +
    +  public BytesToBytesMap(MemoryManager memoryManager, int initialCapacity) {
    +    this(memoryManager, initialCapacity, 0.70, false);
    +  }
    +
    +  public BytesToBytesMap(
    +      MemoryManager memoryManager,
    +      int initialCapacity,
    +      boolean enablePerfMetrics) {
    +    this(memoryManager, initialCapacity, 0.70, enablePerfMetrics);
    +  }
    +
    +  @Override
    +  protected void finalize() throws Throwable {
    +    try {
    +      // In case the programmer forgot to call `free()`, try to perform that cleanup now:
    +      free();
    +    } finally {
    +      super.finalize();
    +    }
    +  }
    +
    +  /**
    +   * Returns the number of keys defined in the map.
    +   */
    +  public int size() { return size; }
    +
    +  /**
    +   * Returns an iterator for iterating over the entries of this map.
    +   *
    +   * For efficiency, all calls to `next()` will return the same {@link Location} object.
    +   *
    +   * If any other lookups or operations are performed on this map while iterating over it, including
    +   * `lookup()`, the behavior of the returned iterator is undefined.
    +   */
    +  public Iterator<Location> iterator() {
    +    return new Iterator<Location>() {
    +
    +      private int nextPos = bitset.nextSetBit(0);
    +
    +      @Override
    +      public boolean hasNext() {
    +        return nextPos != -1;
    +      }
    +
    +      @Override
    +      public Location next() {
    +        final int pos = nextPos;
    +        nextPos = bitset.nextSetBit(nextPos + 1);
    +        return loc.with(pos, 0, true);
    +      }
    +
    +      @Override
    +      public void remove() {
    +        throw new UnsupportedOperationException();
    +      }
    +    };
    +  }
    +
    +  /**
    +   * Looks up a key, and return a {@link Location} handle that can be used to test existence
    +   * and read/write values.
    +   *
    +   * This function always return the same {@link Location} instance to avoid object allocation.
    +   */
    +  public Location lookup(
    +      Object keyBaseObject,
    +      long keyBaseOffset,
    +      int keyRowLengthBytes) {
    +    if (enablePerfMetrics) {
    +      numKeyLookups++;
    +    }
    +    final int hashcode = HASHER.hashUnsafeWords(keyBaseObject, keyBaseOffset, keyRowLengthBytes);
    +    int pos = hashcode & mask;
    +    int step = 1;
    +    while (true) {
    +      if (enablePerfMetrics) {
    +        numProbes++;
    +      }
    +      if (!bitset.isSet(pos)) {
    +        // This is a new key.
    +        return loc.with(pos, hashcode, false);
    +      } else {
    +        long stored = longArray.get(pos * 2 + 1);
    +        if ((int) (stored) == hashcode) {
    +          // Full hash code matches.  Let's compare the keys for equality.
    +          loc.with(pos, hashcode, true);
    +          if (loc.getKeyLength() == keyRowLengthBytes) {
    +            final MemoryLocation keyAddress = loc.getKeyAddress();
    +            final Object storedKeyBaseObject = keyAddress.getBaseObject();
    +            final long storedKeyBaseOffset = keyAddress.getBaseOffset();
    +            final boolean areEqual = ByteArrayMethods.wordAlignedArrayEquals(
    +              keyBaseObject,
    +              keyBaseOffset,
    +              storedKeyBaseObject,
    +              storedKeyBaseOffset,
    +              keyRowLengthBytes
    +            );
    +            if (areEqual) {
    +              return loc;
    +            } else {
    +              if (enablePerfMetrics) {
    +                numHashCollisions++;
    +              }
    +            }
    +          }
    +        }
    +      }
    +      pos = (pos + step) & mask;
    +      step++;
    +    }
    +  }
    +
    +  /**
    +   * Handle returned by {@link BytesToBytesMap#lookup(Object, long, int)} function.
    +   */
    +  public final class Location {
    +    /** An index into the hash map's Long array */
    +    private int pos;
    +    /** True if this location points to a position where a key is defined, false otherwise */
    +    private boolean isDefined;
    +    /**
    +     * The hashcode of the most recent key passed to
    +     * {@link BytesToBytesMap#lookup(Object, long, int)}. Caching this hashcode here allows us to
    +     * avoid re-hashing the key when storing a value for that key.
    +     */
    +    private int keyHashcode;
    +    private final MemoryLocation keyMemoryLocation = new MemoryLocation();
    +    private final MemoryLocation valueMemoryLocation = new MemoryLocation();
    +    private int keyLength;
    +    private int valueLength;
    +
    +    private void updateAddressesAndSizes(long fullKeyAddress) {
    +        final Object page = memoryManager.getPage(fullKeyAddress);
    +        final long keyOffsetInPage = memoryManager.getOffsetInPage(fullKeyAddress);
    +        keyMemoryLocation.setObjAndOffset(page, keyOffsetInPage + 8);
    +        keyLength = (int) PlatformDependent.UNSAFE.getLong(page, keyOffsetInPage);
    +        valueMemoryLocation.setObjAndOffset(page, keyOffsetInPage + 8 + keyLength + 8);
    +        valueLength = (int) PlatformDependent.UNSAFE.getLong(page, keyOffsetInPage + 8 + keyLength);
    +    }
    +
    +    Location with(int pos, int keyHashcode, boolean isDefined) {
    +      this.pos = pos;
    +      this.isDefined = isDefined;
    +      this.keyHashcode = keyHashcode;
    +      if (isDefined) {
    +        final long fullKeyAddress = longArray.get(pos * 2);
    +        updateAddressesAndSizes(fullKeyAddress);
    +      }
    +      return this;
    +    }
    +
    +    /**
    +     * Returns true if the key is defined at this position, and false otherwise.
    +     */
    +    public boolean isDefined() {
    +      return isDefined;
    +    }
    +
    +    /**
    +     * Returns the address of the key defined at this position.
    +     * This points to the first byte of the key data.
    +     * Unspecified behavior if the key is not defined.
    +     * For efficiency reasons, calls to this method always returns the same MemoryLocation object.
    +     */
    +    public MemoryLocation getKeyAddress() {
    +      assert (isDefined);
    +      return keyMemoryLocation;
    +    }
    +
    +    /**
    +     * Returns the length of the key defined at this position.
    +     * Unspecified behavior if the key is not defined.
    +     */
    +    public int getKeyLength() {
    +      assert (isDefined);
    +      return keyLength;
    +    }
    +
    +    /**
    +     * Returns the address of the value defined at this position.
    +     * This points to the first byte of the value data.
    +     * Unspecified behavior if the key is not defined.
    +     * For efficiency reasons, calls to this method always returns the same MemoryLocation object.
    +     */
    +    public MemoryLocation getValueAddress() {
    +      assert (isDefined);
    +      return valueMemoryLocation;
    +    }
    +
    +    /**
    +     * Returns the length of the value defined at this position.
    +     * Unspecified behavior if the key is not defined.
    +     */
    +    public int getValueLength() {
    +      assert (isDefined);
    +      return valueLength;
    +    }
    +
    +    /**
    +     * Store a new key and value. This method may only be called once for a given key; if you want
    +     * to update the value associated with a key, then you can directly manipulate the bytes stored
    +     * at the value address.
    +     * <p>
    +     * It is only valid to call this method immediately after calling `lookup()` using the same key.
    +     * <p>
    +     * After calling this method, calls to `get[Key|Value]Address()` and `get[Key|Value]Length`
    +     * will return information on the data stored by this `putNewKey` call.
    +     * <p>
    +     * As an example usage, here's the proper way to store a new key:
    +     * <p>
    +     * <pre>
    +     *   Location loc = map.lookup(keyBaseOffset, keyBaseObject, keyLengthInBytes);
    +     *   if (!loc.isDefined()) {
    +     *     loc.putNewKey(keyBaseOffset, keyBaseObject, keyLengthInBytes, ...)
    +     *   }
    +     * </pre>
    +     * <p>
    +     * Unspecified behavior if the key is not defined.
    +     */
    +    public void putNewKey(
    +        Object keyBaseObject,
    +        long keyBaseOffset,
    +        int keyLengthBytes,
    +        Object valueBaseObject,
    +        long valueBaseOffset,
    +        int valueLengthBytes) {
    +      assert (!isDefined) : "Can only set value once for a key";
    +      isDefined = true;
    +      assert (keyLengthBytes % 8 == 0);
    +      assert (valueLengthBytes % 8 == 0);
    +      // Here, we'll copy the data into our data pages. Because we only store a relative offset from
    +      // the key address instead of storing the absolute address of the value, the key and value
    +      // must be stored in the same memory page.
    +      final long requiredSize = 8 + 8 + keyLengthBytes + valueLengthBytes;
    --- End diff --
    
    Yep, that's key length and value length.  I use the same pattern in a couple of other places, so maybe I can pull this into a constant or add comments there, too.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by marmbrus <gi...@git.apache.org>.
Github user marmbrus commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29301372
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -41,13 +42,15 @@ case class AggregateEvaluation(
      * @param groupingExpressions expressions that are evaluated to determine grouping.
      * @param aggregateExpressions expressions that are computed for each group.
      * @param child the input data source.
    + * @param unsafeEnabled whether to allow Unsafe-based aggregation buffers to be used.
      */
     @DeveloperApi
     case class GeneratedAggregate(
         partial: Boolean,
         groupingExpressions: Seq[Expression],
         aggregateExpressions: Seq[NamedExpression],
    -    child: SparkPlan)
    +    child: SparkPlan,
    +    unsafeEnabled: Boolean)
    --- End diff --
    
    nit: typically place children last (although we aren't great about following this convention)...


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97280969
  
    Merged build started.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97284005
  
    Merged build finished. Test FAILed.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97203797
  
      [Test build #31173 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31173/consoleFull) for   PR 5725 at commit [`a19e066`](https://github.com/apache/spark/commit/a19e0661ac9338d2856883537e314296607901a4).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29215924
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeRow.java ---
    @@ -0,0 +1,428 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import scala.collection.Map;
    +import scala.collection.Seq;
    +import scala.collection.mutable.ArraySeq;
    +
    +import javax.annotation.Nullable;
    +import java.math.BigDecimal;
    +import java.sql.Date;
    +import java.util.*;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.DataType;
    +import static org.apache.spark.sql.types.DataTypes.*;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.sql.types.UTF8String;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.bitset.BitSetMethods;
    +
    +/**
    + * An Unsafe implementation of Row which is backed by raw memory instead of Java objects.
    + *
    + * Each tuple has three parts: [null bit set] [values] [variable length portion]
    + *
    + * The bit set is used for null tracking and is aligned to 8-byte word boundaries.  It stores
    + * one bit per field.
    + *
    + * In the `values` region, we store one 8-byte word per field. For fields that hold fixed-length
    + * primitive types, such as long, double, or int, we store the value directly in the word. For
    + * fields with non-primitive or variable-length values, we store a relative offset (w.r.t. the
    + * base address of the row) that points to the beginning of the variable-length field.
    + *
    + * Instances of `UnsafeRow` act as pointers to row data stored in this format, similar to how
    + * `Writable` objects work in Hadoop.
    + */
    +public final class UnsafeRow implements MutableRow {
    +
    +  private Object baseObject;
    +  private long baseOffset;
    +  /** The number of fields in this row, used for calculating the bitset width (and in assertions) */
    +  private int numFields;
    +  /** The width of the null tracking bit set, in bytes */
    +  private int bitSetWidthInBytes;
    +  /**
    +   * This optional schema is required if you want to call generic get() and set() methods on
    +   * this UnsafeRow, but is optional if callers will only use type-specific getTYPE() and setTYPE()
    +   * methods.
    +   */
    +  @Nullable
    +  private StructType schema;
    --- End diff --
    
    I think we can remove this -- since internally we never use this.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by marmbrus <gi...@git.apache.org>.
Github user marmbrus commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29303434
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -265,7 +283,49 @@ case class GeneratedAggregate(
     
             val resultProjection = resultProjectionBuilder()
             Iterator(resultProjection(buffer))
    +      } else if (unsafeEnabled && schemaSupportsUnsafe) {
    --- End diff --
    
    Similar to my comment above, I think it would be better if this decision was made in the query planner.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by tgravescs <gi...@git.apache.org>.
Github user tgravescs commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97828392
  
    I'm not able to build after this went  in.  Any special requirements to build this?
    
    [info] Compiling 15 Java sources to /home/tgraves/tgravescs_spark/unsafe/target/scala-2.10/classes...
    [error] /home/tgraves/tgravescs_spark/unsafe/src/main/java/org/apache/spark/unsafe/PlatformDependent.java:22: warning: sun.misc.Unsafe is Sun proprietary API and may be removed in a future release
    [error] import sun.misc.Unsafe;
    [error]                ^
    [error] /home/tgraves/tgravescs_spark/unsafe/src/main/java/org/apache/spark/unsafe/PlatformDependent.java:26: warning: sun.misc.Unsafe is Sun proprietary API and may be removed in a future release
    [error]   public static final Unsafe UNSAFE;
    [error]                       ^
    [error] /home/tgraves/tgravescs_spark/unsafe/src/main/java/org/apache/spark/unsafe/PlatformDependent.java:43: warning: sun.misc.Unsafe is Sun proprietary API and may be removed in a future release
    [error]     sun.misc.Unsafe unsafe;
    [error]             ^
    [error] /home/tgraves/tgravescs_spark/unsafe/src/main/java/org/apache/spark/unsafe/PlatformDependent.java:45: warning: sun.misc.Unsafe is Sun proprietary API and may be removed in a future release
    [error]       Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
    [error]                           ^
    [error] /home/tgraves/tgravescs_spark/unsafe/src/main/java/org/apache/spark/unsafe/PlatformDependent.java:47: warning: sun.misc.Unsafe is Sun proprietary API and may be removed in a future release
    [error]       unsafe = (sun.misc.Unsafe) unsafeField.get(null);
    [error]                         ^
    [error] /home/tgraves/tgravescs_spark/unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryBlock.java:53: setMemory(long,long,byte) in sun.misc.Unsafe cannot be applied to (java.lang.Object,long,long,byte)
    [error]     PlatformDependent.UNSAFE.setMemory(obj, offset, length, (byte) 0);
    [error]                             ^
    [error] 1 error
    [error] 5 warnings
    [error] Compile failed at Apr 30, 2015 2:52:04 PM [0.862s]


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29218879
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeRow.java ---
    @@ -0,0 +1,428 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import scala.collection.Map;
    +import scala.collection.Seq;
    +import scala.collection.mutable.ArraySeq;
    +
    +import javax.annotation.Nullable;
    +import java.math.BigDecimal;
    +import java.sql.Date;
    +import java.util.*;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.DataType;
    +import static org.apache.spark.sql.types.DataTypes.*;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.sql.types.UTF8String;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.bitset.BitSetMethods;
    +
    +/**
    + * An Unsafe implementation of Row which is backed by raw memory instead of Java objects.
    + *
    + * Each tuple has three parts: [null bit set] [values] [variable length portion]
    + *
    + * The bit set is used for null tracking and is aligned to 8-byte word boundaries.  It stores
    + * one bit per field.
    + *
    + * In the `values` region, we store one 8-byte word per field. For fields that hold fixed-length
    + * primitive types, such as long, double, or int, we store the value directly in the word. For
    + * fields with non-primitive or variable-length values, we store a relative offset (w.r.t. the
    + * base address of the row) that points to the beginning of the variable-length field.
    + *
    + * Instances of `UnsafeRow` act as pointers to row data stored in this format, similar to how
    + * `Writable` objects work in Hadoop.
    --- End diff --
    
    how is this similar to writable?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29287003
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryManager.java ---
    @@ -0,0 +1,176 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.BitSet;
    +
    +/**
    + * Manages the lifecycle of data pages exchanged between operators.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    + * numbers are used to index into a "page table" array inside of the MemoryManager in order to
    + * retrieve the base object.
    + */
    +public final class MemoryManager {
    +
    +  /**
    +   * The number of entries in the page table.
    +   */
    +  private static final int PAGE_TABLE_SIZE = (int) 1L << 13;
    +
    +  /** Bit mask for the lower 51 bits of a long. */
    +  private static final long MASK_LONG_LOWER_51_BITS = 0x7FFFFFFFFFFFFL;
    +
    +  /** Bit mask for the upper 13 bits of a long */
    +  private static final long MASK_LONG_UPPER_13_BITS = ~MASK_LONG_LOWER_51_BITS;
    +
    +  /**
    +   * Similar to an operating system's page table, this array maps page numbers into base object
    +   * pointers, allowing us to translate between the hashtable's internal 64-bit address
    +   * representation and the baseObject+offset representation which we use to support both in- and
    +   * off-heap addresses. When using an off-heap allocator, every entry in this map will be `null`.
    +   * When using an in-heap allocator, the entries in this map will point to pages' base objects.
    +   * Entries are added to this map as new data pages are allocated.
    +   */
    +  private final MemoryBlock[] pageTable = new MemoryBlock[PAGE_TABLE_SIZE];
    +
    +  /**
    +   * Bitmap for tracking free pages.
    +   */
    +  private final BitSet allocatedPages = new BitSet(PAGE_TABLE_SIZE);
    +
    +  /**
    +   * Allocator, exposed for enabling untracked allocations of temporary data structures.
    +   */
    +  public final MemoryAllocator allocator;
    +
    +  /**
    +   * Tracks whether we're in-heap or off-heap. For off-heap, we short-circuit most of these methods
    +   * without doing any masking or lookups. Since this branching should be well-predicted by the JIT,
    +   * this extra layer of indirection / abstraction hopefully shouldn't be too expensive.
    +   */
    +  private final boolean inHeap;
    +
    +  /**
    +   * Construct a new MemoryManager.
    +   */
    +  public MemoryManager(MemoryAllocator allocator) {
    +    this.inHeap = allocator instanceof HeapMemoryAllocator;
    +    this.allocator = allocator;
    +  }
    +
    +  /**
    +   * Allocate a block of memory that will be tracked in the MemoryManager's page table; this is
    +   * intended for allocating large blocks of memory that will be shared between operators.
    +   */
    +  public MemoryBlock allocatePage(long size) {
    --- End diff --
    
    Done.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97263384
  
    **[Test build #31173 timed out](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31173/consoleFull)**     for PR 5725 at commit [`a19e066`](https://github.com/apache/spark/commit/a19e0661ac9338d2856883537e314296607901a4)     after a configured wait of `150m`.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29215645
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/SparkStrategies.scala ---
    @@ -140,7 +140,9 @@ private[sql] abstract class SparkStrategies extends QueryPlanner[SparkPlan] {
                   partial = true,
                   groupingExpressions,
                   partialComputation,
    -              planLater(child))) :: Nil
    +              planLater(child),
    +              unsafeEnabled),
    +          unsafeEnabled) :: Nil
    --- End diff --
    
    indent off here


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29221210
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryManager.java ---
    @@ -0,0 +1,176 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.BitSet;
    +
    +/**
    + * Manages the lifecycle of data pages exchanged between operators.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    --- End diff --
    
    we should spell out the total number of pages and memory addressable with this encoding


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29220523
  
    --- Diff: sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/UnsafeRowConverter.scala ---
    @@ -0,0 +1,226 @@
    +/*
    + * 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.spark.sql.catalyst.expressions
    +
    +import org.apache.spark.sql.types._
    +import org.apache.spark.unsafe.PlatformDependent
    +import org.apache.spark.unsafe.array.ByteArrayMethods
    +
    +/**
    + * Converts Rows into UnsafeRow format. This class is NOT thread-safe.
    + *
    + * @param fieldTypes the data types of the row's columns.
    + */
    +class UnsafeRowConverter(fieldTypes: Array[DataType]) {
    +
    +  def this(schema: StructType) {
    +    this(schema.fields.map(_.dataType))
    +  }
    +
    +  /** Re-used pointer to the unsafe row being written */
    +  private[this] val unsafeRow = new UnsafeRow()
    +
    +  /** Functions for encoding each column */
    +  private[this] val writers: Array[UnsafeColumnWriter[Any]] = {
    +    fieldTypes.map(t => UnsafeColumnWriter.forType(t).asInstanceOf[UnsafeColumnWriter[Any]])
    +  }
    +
    +  /** The size, in bytes, of the fixed-length portion of the row, including the null bitmap */
    +  private[this] val fixedLengthSize: Int =
    +    (8 * fieldTypes.length) + UnsafeRow.calculateBitSetWidthInBytes(fieldTypes.length)
    +
    +  /**
    +   * Compute the amount of space, in bytes, required to encode the given row.
    +   */
    +  def getSizeRequirement(row: Row): Int = {
    +    var fieldNumber = 0
    +    var variableLengthFieldSize: Int = 0
    +    while (fieldNumber < writers.length) {
    +      if (!row.isNullAt(fieldNumber)) {
    +        variableLengthFieldSize += writers(fieldNumber).getSize(row(fieldNumber))
    +      }
    +      fieldNumber += 1
    +    }
    +    fixedLengthSize + variableLengthFieldSize
    +  }
    +
    +  /**
    +   * Convert the given row into UnsafeRow format.
    +   *
    +   * @param row the row to convert
    +   * @param baseObject the base object of the destination address
    +   * @param baseOffset the base offset of the destination address
    +   * @return the number of bytes written. This should be equal to `getSizeRequirement(row)`.
    +   */
    +  def writeRow(row: Row, baseObject: Object, baseOffset: Long): Long = {
    +    unsafeRow.pointTo(baseObject, baseOffset, writers.length, null)
    +    var fieldNumber = 0
    +    var appendCursor: Int = fixedLengthSize
    +    while (fieldNumber < writers.length) {
    +      if (row.isNullAt(fieldNumber)) {
    +        unsafeRow.setNullAt(fieldNumber)
    +      } else {
    +        appendCursor += writers(fieldNumber).write(
    +          row(fieldNumber),
    +          fieldNumber,
    +          unsafeRow,
    +          baseObject,
    +          baseOffset,
    +          appendCursor)
    +      }
    +      fieldNumber += 1
    +    }
    +    appendCursor
    +  }
    +
    +}
    +
    +/**
    + * Function for writing a column into an UnsafeRow.
    + */
    +private abstract class UnsafeColumnWriter[T] {
    +  /**
    +   * Write a value into an UnsafeRow.
    +   *
    +   * @param value the value to write
    +   * @param columnNumber what column to write it to
    +   * @param row a pointer to the unsafe row
    +   * @param baseObject the base object of the target row's address
    +   * @param baseOffset the base offset of the target row's address
    +   * @param appendCursor the offset from the start of the unsafe row to the end of the row;
    +   *                     used for calculating where variable-length data should be written
    +   * @return the number of variable-length bytes written
    +   */
    +  def write(
    +      value: T,
    +      columnNumber: Int,
    +      row: UnsafeRow,
    +      baseObject: Object,
    +      baseOffset: Long,
    +      appendCursor: Int): Int
    +
    +  /**
    +   * Return the number of bytes that are needed to write this variable-length value.
    +   */
    +  def getSize(value: T): Int
    +}
    +
    +private object UnsafeColumnWriter {
    +
    +  def forType(dataType: DataType): UnsafeColumnWriter[_] = {
    +    dataType match {
    +      case IntegerType => IntUnsafeColumnWriter
    +      case LongType => LongUnsafeColumnWriter
    +      case FloatType => FloatUnsafeColumnWriter
    +      case DoubleType => DoubleUnsafeColumnWriter
    +      case StringType => StringUnsafeColumnWriter
    +      case t =>
    +        throw new UnsupportedOperationException(s"Do not know how to write columns of type $t")
    +    }
    +  }
    +}
    +
    +// ------------------------------------------------------------------------------------------------
    +
    +private object IntUnsafeColumnWriter extends IntUnsafeColumnWriter
    +private object LongUnsafeColumnWriter extends LongUnsafeColumnWriter
    +private object FloatUnsafeColumnWriter extends FloatUnsafeColumnWriter
    +private object DoubleUnsafeColumnWriter extends DoubleUnsafeColumnWriter
    +private object StringUnsafeColumnWriter extends StringUnsafeColumnWriter
    +
    +private abstract class PrimitiveUnsafeColumnWriter[T] extends UnsafeColumnWriter[T] {
    +  def getSize(value: T): Int = 0
    +}
    +
    +private class IntUnsafeColumnWriter private() extends PrimitiveUnsafeColumnWriter[Int] {
    +  override def write(
    --- End diff --
    
    can u define the return value?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97272168
  
      [Test build #31185 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31185/consoleFull) for   PR 5725 at commit [`70a39e4`](https://github.com/apache/spark/commit/70a39e4fe05c31ac73b99614115f1fe9f150e1e6).
     * This patch **fails Spark unit tests**.
     * This patch merges cleanly.
     * This patch adds the following public classes _(experimental)_:
      * `public final class UnsafeFixedWidthAggregationMap `
      * `  public static class MapEntry `
      * `public final class UnsafeRow implements MutableRow `
      * `class UnsafeRowConverter(fieldTypes: Array[DataType]) `
      * `public final class PlatformDependent `
      * `public class ByteArrayMethods `
      * `public final class LongArray `
      * `public final class BitSet `
      * `public final class BitSetMethods `
      * `public final class Murmur3_x86_32 `
      * `public final class BytesToBytesMap `
      * `  public final class Location `
      * `  class Doubling implements HashMapGrowthStrategy `
      * `public class ExecutorMemoryManager `
      * `public class HeapMemoryAllocator implements MemoryAllocator `
      * `public class MemoryBlock extends MemoryLocation `
      * `public class MemoryLocation `
      * `public final class TaskMemoryManager `
      * `public class UnsafeMemoryAllocator implements MemoryAllocator `
    
     * This patch **adds the following new dependencies:**
       * `spark-unsafe_2.10-1.4.0-SNAPSHOT.jar`



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97311160
  
     Merged build triggered.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29300182
  
    --- Diff: core/src/main/scala/org/apache/spark/executor/Executor.scala ---
    @@ -207,7 +210,23 @@ private[spark] class Executor(
     
             // Run the actual task and measure its runtime.
             taskStart = System.currentTimeMillis()
    -        val value = task.run(taskAttemptId = taskId, attemptNumber = attemptNumber)
    +        var succeeded: Boolean = false
    +        val value = try {
    +          val value = task.run(taskAttemptId = taskId, attemptNumber = attemptNumber)
    +          succeeded = true
    +          value
    +        } finally {
    +          // Release managed memory used by this task
    +          val freedMemory = taskMemoryManager.cleanUpAllAllocatedMemory()
    +          if (succeeded && freedMemory > 0) {
    --- End diff --
    
    maybe we want to enforce so that even in the case of failures, memory should be cleaned up?
    
    also would be great to not have two different code path in executor vs dagscheduler


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29267770
  
    --- Diff: sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/UnsafeRowConverter.scala ---
    @@ -0,0 +1,226 @@
    +/*
    + * 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.spark.sql.catalyst.expressions
    +
    +import org.apache.spark.sql.types._
    +import org.apache.spark.unsafe.PlatformDependent
    +import org.apache.spark.unsafe.array.ByteArrayMethods
    +
    +/**
    + * Converts Rows into UnsafeRow format. This class is NOT thread-safe.
    + *
    + * @param fieldTypes the data types of the row's columns.
    + */
    +class UnsafeRowConverter(fieldTypes: Array[DataType]) {
    +
    +  def this(schema: StructType) {
    +    this(schema.fields.map(_.dataType))
    +  }
    +
    +  /** Re-used pointer to the unsafe row being written */
    +  private[this] val unsafeRow = new UnsafeRow()
    +
    +  /** Functions for encoding each column */
    +  private[this] val writers: Array[UnsafeColumnWriter[Any]] = {
    +    fieldTypes.map(t => UnsafeColumnWriter.forType(t).asInstanceOf[UnsafeColumnWriter[Any]])
    +  }
    +
    +  /** The size, in bytes, of the fixed-length portion of the row, including the null bitmap */
    +  private[this] val fixedLengthSize: Int =
    +    (8 * fieldTypes.length) + UnsafeRow.calculateBitSetWidthInBytes(fieldTypes.length)
    +
    +  /**
    +   * Compute the amount of space, in bytes, required to encode the given row.
    +   */
    +  def getSizeRequirement(row: Row): Int = {
    +    var fieldNumber = 0
    +    var variableLengthFieldSize: Int = 0
    +    while (fieldNumber < writers.length) {
    +      if (!row.isNullAt(fieldNumber)) {
    +        variableLengthFieldSize += writers(fieldNumber).getSize(row(fieldNumber))
    +      }
    +      fieldNumber += 1
    +    }
    +    fixedLengthSize + variableLengthFieldSize
    +  }
    +
    +  /**
    +   * Convert the given row into UnsafeRow format.
    +   *
    +   * @param row the row to convert
    +   * @param baseObject the base object of the destination address
    +   * @param baseOffset the base offset of the destination address
    +   * @return the number of bytes written. This should be equal to `getSizeRequirement(row)`.
    +   */
    +  def writeRow(row: Row, baseObject: Object, baseOffset: Long): Long = {
    +    unsafeRow.pointTo(baseObject, baseOffset, writers.length, null)
    +    var fieldNumber = 0
    +    var appendCursor: Int = fixedLengthSize
    +    while (fieldNumber < writers.length) {
    +      if (row.isNullAt(fieldNumber)) {
    +        unsafeRow.setNullAt(fieldNumber)
    +      } else {
    +        appendCursor += writers(fieldNumber).write(
    +          row(fieldNumber),
    +          fieldNumber,
    +          unsafeRow,
    +          baseObject,
    +          baseOffset,
    +          appendCursor)
    +      }
    +      fieldNumber += 1
    +    }
    +    appendCursor
    +  }
    +
    +}
    +
    +/**
    + * Function for writing a column into an UnsafeRow.
    + */
    +private abstract class UnsafeColumnWriter[T] {
    +  /**
    +   * Write a value into an UnsafeRow.
    +   *
    +   * @param value the value to write
    +   * @param columnNumber what column to write it to
    +   * @param row a pointer to the unsafe row
    +   * @param baseObject the base object of the target row's address
    +   * @param baseOffset the base offset of the target row's address
    +   * @param appendCursor the offset from the start of the unsafe row to the end of the row;
    +   *                     used for calculating where variable-length data should be written
    +   * @return the number of variable-length bytes written
    +   */
    +  def write(
    +      value: T,
    +      columnNumber: Int,
    +      row: UnsafeRow,
    +      baseObject: Object,
    +      baseOffset: Long,
    +      appendCursor: Int): Int
    +
    +  /**
    +   * Return the number of bytes that are needed to write this variable-length value.
    +   */
    +  def getSize(value: T): Int
    +}
    +
    +private object UnsafeColumnWriter {
    +
    +  def forType(dataType: DataType): UnsafeColumnWriter[_] = {
    +    dataType match {
    +      case IntegerType => IntUnsafeColumnWriter
    +      case LongType => LongUnsafeColumnWriter
    +      case FloatType => FloatUnsafeColumnWriter
    +      case DoubleType => DoubleUnsafeColumnWriter
    +      case StringType => StringUnsafeColumnWriter
    +      case t =>
    +        throw new UnsupportedOperationException(s"Do not know how to write columns of type $t")
    +    }
    +  }
    +}
    +
    +// ------------------------------------------------------------------------------------------------
    +
    +private object IntUnsafeColumnWriter extends IntUnsafeColumnWriter
    +private object LongUnsafeColumnWriter extends LongUnsafeColumnWriter
    +private object FloatUnsafeColumnWriter extends FloatUnsafeColumnWriter
    +private object DoubleUnsafeColumnWriter extends DoubleUnsafeColumnWriter
    +private object StringUnsafeColumnWriter extends StringUnsafeColumnWriter
    +
    +private abstract class PrimitiveUnsafeColumnWriter[T] extends UnsafeColumnWriter[T] {
    +  def getSize(value: T): Int = 0
    +}
    +
    +private class IntUnsafeColumnWriter private() extends PrimitiveUnsafeColumnWriter[Int] {
    +  override def write(
    --- End diff --
    
    The return value is the number of bytes written, which we use to increment the position cursor.  I think that I commented on this in the base `UnsafeColumnWriter` class.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97263416
  
    Merged build finished. Test FAILed.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29221682
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryManager.java ---
    @@ -0,0 +1,176 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.BitSet;
    +
    +/**
    + * Manages the lifecycle of data pages exchanged between operators.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    + * numbers are used to index into a "page table" array inside of the MemoryManager in order to
    + * retrieve the base object.
    + */
    +public final class MemoryManager {
    +
    +  /**
    +   * The number of entries in the page table.
    +   */
    +  private static final int PAGE_TABLE_SIZE = (int) 1L << 13;
    +
    +  /** Bit mask for the lower 51 bits of a long. */
    +  private static final long MASK_LONG_LOWER_51_BITS = 0x7FFFFFFFFFFFFL;
    +
    +  /** Bit mask for the upper 13 bits of a long */
    +  private static final long MASK_LONG_UPPER_13_BITS = ~MASK_LONG_LOWER_51_BITS;
    +
    +  /**
    +   * Similar to an operating system's page table, this array maps page numbers into base object
    +   * pointers, allowing us to translate between the hashtable's internal 64-bit address
    +   * representation and the baseObject+offset representation which we use to support both in- and
    +   * off-heap addresses. When using an off-heap allocator, every entry in this map will be `null`.
    +   * When using an in-heap allocator, the entries in this map will point to pages' base objects.
    +   * Entries are added to this map as new data pages are allocated.
    +   */
    +  private final MemoryBlock[] pageTable = new MemoryBlock[PAGE_TABLE_SIZE];
    +
    +  /**
    +   * Bitmap for tracking free pages.
    +   */
    +  private final BitSet allocatedPages = new BitSet(PAGE_TABLE_SIZE);
    +
    +  /**
    +   * Allocator, exposed for enabling untracked allocations of temporary data structures.
    +   */
    +  public final MemoryAllocator allocator;
    +
    +  /**
    +   * Tracks whether we're in-heap or off-heap. For off-heap, we short-circuit most of these methods
    +   * without doing any masking or lookups. Since this branching should be well-predicted by the JIT,
    +   * this extra layer of indirection / abstraction hopefully shouldn't be too expensive.
    +   */
    +  private final boolean inHeap;
    +
    +  /**
    +   * Construct a new MemoryManager.
    +   */
    +  public MemoryManager(MemoryAllocator allocator) {
    +    this.inHeap = allocator instanceof HeapMemoryAllocator;
    +    this.allocator = allocator;
    +  }
    +
    +  /**
    +   * Allocate a block of memory that will be tracked in the MemoryManager's page table; this is
    +   * intended for allocating large blocks of memory that will be shared between operators.
    +   */
    +  public MemoryBlock allocatePage(long size) {
    +    if (size >= (1L << 51)) {
    +      throw new IllegalArgumentException("Cannot allocate a page with more than 2^51 bytes");
    +    }
    +
    +    final int pageNumber;
    +    synchronized (this) {
    +      pageNumber = allocatedPages.nextClearBit(0);
    +      if (pageNumber >= PAGE_TABLE_SIZE) {
    +        throw new IllegalStateException(
    +          "Have already allocated a maximum of " + PAGE_TABLE_SIZE + " pages");
    +      }
    +      allocatedPages.set(pageNumber);
    +    }
    +    final MemoryBlock page = allocator.allocate(size);
    +    page.pageNumber = pageNumber;
    +    pageTable[pageNumber] = page;
    +    return page;
    +  }
    +
    +  /**
    +   * Free a block of memory allocated via {@link MemoryManager#allocatePage(long)}.
    +   */
    +  public void freePage(MemoryBlock page) {
    --- End diff --
    
    and log something here too


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96870193
  
      [Test build #31095 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31095/consoleFull) for   PR 5725 at commit [`a8e4a3f`](https://github.com/apache/spark/commit/a8e4a3fe40574c3a609beeb4794b11bd720a31e7).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29273686
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeRow.java ---
    @@ -0,0 +1,428 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import scala.collection.Map;
    +import scala.collection.Seq;
    +import scala.collection.mutable.ArraySeq;
    +
    +import javax.annotation.Nullable;
    +import java.math.BigDecimal;
    +import java.sql.Date;
    +import java.util.*;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.DataType;
    +import static org.apache.spark.sql.types.DataTypes.*;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.sql.types.UTF8String;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.bitset.BitSetMethods;
    +
    +/**
    + * An Unsafe implementation of Row which is backed by raw memory instead of Java objects.
    + *
    + * Each tuple has three parts: [null bit set] [values] [variable length portion]
    + *
    + * The bit set is used for null tracking and is aligned to 8-byte word boundaries.  It stores
    + * one bit per field.
    + *
    + * In the `values` region, we store one 8-byte word per field. For fields that hold fixed-length
    + * primitive types, such as long, double, or int, we store the value directly in the word. For
    + * fields with non-primitive or variable-length values, we store a relative offset (w.r.t. the
    + * base address of the row) that points to the beginning of the variable-length field.
    + *
    + * Instances of `UnsafeRow` act as pointers to row data stored in this format, similar to how
    + * `Writable` objects work in Hadoop.
    --- End diff --
    
    It's a very superficial similarity in the sense that both are mutable objects that are used to expose data that's backed by something that's serialized. This comment is confusing, though, so I'm going to remove it.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by tedyu <gi...@git.apache.org>.
Github user tedyu commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97511381
  
    
    
    
    
    
    
    
    
    <sup>**[sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeFixedWidthAggregationMap.java, line 133 \[r14\]](https://reviewable.io:443/reviews/apache/spark/5725#-Jo56lmUPtN4oJEAxApu)** ([raw file](https://github.com/apache/spark/blob/eeee512bd94d463f741170e904ae186e238f997c/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeFixedWidthAggregationMap.java#L133)):</sup>
    Please include writtenLength, unsafeRow.length and javaRow in the assertion so that we have more information when debugging.
    
    ---
    
    <sup>**[sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeRow.java, line 148 \[r14\]](https://reviewable.io:443/reviews/apache/spark/5725#-Jo57pOAjJQa1nPxxd2y)** ([raw file](https://github.com/apache/spark/blob/eeee512bd94d463f741170e904ae186e238f997c/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeRow.java#L148)):</sup>
    Condition doesn't match assertion message w.r.t. <=
    
    ---
    
    <sup>**[unsafe/src/main/java/org/apache/spark/unsafe/array/ByteArrayMethods.java, line 23 \[r14\]](https://reviewable.io:443/reviews/apache/spark/5725#-Jo5AmeniFC0_bDQdiyb)** ([raw file](https://github.com/apache/spark/blob/eeee512bd94d463f741170e904ae186e238f997c/unsafe/src/main/java/org/apache/spark/unsafe/array/ByteArrayMethods.java#L23)):</sup>
    Declare this class static ?
    
    ---
    
    <sup>**[unsafe/src/main/java/org/apache/spark/unsafe/array/LongArray.java, line 26 \[r14\]](https://reviewable.io:443/reviews/apache/spark/5725#-Jo5B0VcBmjKX4TnrZD7)** ([raw file](https://github.com/apache/spark/blob/eeee512bd94d463f741170e904ae186e238f997c/unsafe/src/main/java/org/apache/spark/unsafe/array/LongArray.java#L26)):</sup>
    nit: in-heap -> on-heap
    
    ---
    
    <sup>**[unsafe/src/main/java/org/apache/spark/unsafe/bitset/BitSet.java, line 24 \[r14\]](https://reviewable.io:443/reviews/apache/spark/5725#-Jo5BT5TTxBoPNV_juFI)** ([raw file](https://github.com/apache/spark/blob/eeee512bd94d463f741170e904ae186e238f997c/unsafe/src/main/java/org/apache/spark/unsafe/bitset/BitSet.java#L24)):</sup>
    https://docs.oracle.com/javase/7/docs/api/java/util/BitSet.html doesn't serve your needs ?
    
    ---
    
    <sup>**[unsafe/src/main/java/org/apache/spark/unsafe/bitset/BitSetMethods.java, line 75 \[r14\]](https://reviewable.io:443/reviews/apache/spark/5725#-Jo5C4Ty7HYh-hvVPSEb)** ([raw file](https://github.com/apache/spark/blob/eeee512bd94d463f741170e904ae186e238f997c/unsafe/src/main/java/org/apache/spark/unsafe/bitset/BitSetMethods.java#L75)):</sup>
    Maybe use something similar to http://www.docjar.com/docs/api/sun/misc/Unsafe.html#getInt(Object, long) for speedup ?
    
    ---
    
    
    ---
    
    Comments from the [review on Reviewable.io](https://reviewable.io:443/reviews/apache/spark/5725)
    <!-- Sent from Reviewable.io -->



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96814367
  
      [Test build #31069 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31069/consoleFull) for   PR 5725 at commit [`0925847`](https://github.com/apache/spark/commit/092584701277394a704c7600c6a631326d7895c6).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29301548
  
    --- Diff: core/src/main/scala/org/apache/spark/executor/Executor.scala ---
    @@ -207,7 +210,23 @@ private[spark] class Executor(
     
             // Run the actual task and measure its runtime.
             taskStart = System.currentTimeMillis()
    -        val value = task.run(taskAttemptId = taskId, attemptNumber = attemptNumber)
    +        var succeeded: Boolean = false
    +        val value = try {
    +          val value = task.run(taskAttemptId = taskId, attemptNumber = attemptNumber)
    +          succeeded = true
    +          value
    +        } finally {
    +          // Release managed memory used by this task
    +          val freedMemory = taskMemoryManager.cleanUpAllAllocatedMemory()
    +          if (succeeded && freedMemory > 0) {
    --- End diff --
    
    I also agree that we should enforce this for failures as well.  In the worst case, I suppose our failure message is masked by a memory leak message, but that's fine for now as this is disabled by default and is only used in tests.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97272175
  
    Merged build finished. Test FAILed.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29218448
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeFixedWidthAggregationMap.java ---
    @@ -0,0 +1,251 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import java.util.Arrays;
    +import java.util.Iterator;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.StructField;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.map.BytesToBytesMap;
    +import org.apache.spark.unsafe.memory.MemoryLocation;
    +import org.apache.spark.unsafe.memory.MemoryManager;
    +
    +/**
    + * Unsafe-based HashMap for performing aggregations where the aggregated values are fixed-width.
    + *
    + * This map supports a maximum of 2 billion keys.
    + */
    +public final class UnsafeFixedWidthAggregationMap {
    +
    +  /**
    +   * An empty aggregation buffer, encoded in UnsafeRow format. When inserting a new key into the
    +   * map, we copy this buffer and use it as the value.
    +   */
    +  private final long[] emptyAggregationBuffer;
    +
    +  private final StructType aggregationBufferSchema;
    +
    +  private final StructType groupingKeySchema;
    +
    +  /**
    +   * Encodes grouping keys as UnsafeRows.
    +   */
    +  private final UnsafeRowConverter groupingKeyToUnsafeRowConverter;
    +
    +  /**
    +   * A hashmap which maps from opaque bytearray keys to bytearray values.
    +   */
    +  private final BytesToBytesMap map;
    +
    +  /**
    +   * Re-used pointer to the current aggregation buffer
    +   */
    +  private final UnsafeRow currentAggregationBuffer = new UnsafeRow();
    +
    +  /**
    +   * Scratch space that is used when encoding grouping keys into UnsafeRow format.
    +   *
    +   * By default, this is a 1MB array, but it will grow as necessary in case larger keys are
    +   * encountered.
    +   */
    +  private long[] groupingKeyConversionScratchSpace = new long[1024 / 8];
    +
    +  private final boolean enablePerfMetrics;
    +
    +  /**
    +   * @return true if UnsafeFixedWidthAggregationMap supports grouping keys with the given schema,
    +   *         false otherwise.
    +   */
    +  public static boolean supportsGroupKeySchema(StructType schema) {
    +    for (StructField field: schema.fields()) {
    +      if (!UnsafeRow.readableFieldTypes.contains(field.dataType())) {
    +        return false;
    +      }
    +    }
    +    return true;
    +  }
    +
    +  /**
    +   * @return true if UnsafeFixedWidthAggregationMap supports aggregation buffers with the given
    +   *         schema, false otherwise.
    +   */
    +  public static boolean supportsAggregationBufferSchema(StructType schema) {
    +    for (StructField field: schema.fields()) {
    +      if (!UnsafeRow.settableFieldTypes.contains(field.dataType())) {
    +        return false;
    +      }
    +    }
    +    return true;
    +  }
    +
    +  /**
    +   * Create a new UnsafeFixedWidthAggregationMap.
    +   *
    +   * @param emptyAggregationBuffer the default value for new keys (a "zero" of the agg. function)
    +   * @param aggregationBufferSchema the schema of the aggregation buffer, used for row conversion.
    +   * @param groupingKeySchema the schema of the grouping key, used for row conversion.
    +   * @param groupingKeySchema the memory manager used to allocate our Unsafe memory structures.
    +   * @param initialCapacity the initial capacity of the map (a sizing hint to avoid re-hashing).
    +   * @param enablePerfMetrics if true, performance metrics will be recorded (has minor perf impact)
    +   */
    +  public UnsafeFixedWidthAggregationMap(
    +      Row emptyAggregationBuffer,
    +      StructType aggregationBufferSchema,
    +      StructType groupingKeySchema,
    +      MemoryManager memoryManager,
    +      int initialCapacity,
    +      boolean enablePerfMetrics) {
    +    this.emptyAggregationBuffer =
    +      convertToUnsafeRow(emptyAggregationBuffer, aggregationBufferSchema);
    +    this.aggregationBufferSchema = aggregationBufferSchema;
    +    this.groupingKeyToUnsafeRowConverter = new UnsafeRowConverter(groupingKeySchema);
    +    this.groupingKeySchema = groupingKeySchema;
    +    this.map = new BytesToBytesMap(memoryManager, initialCapacity, enablePerfMetrics);
    +    this.enablePerfMetrics = enablePerfMetrics;
    +  }
    +
    +  /**
    +   * Convert a Java object row into an UnsafeRow, allocating it into a new long array.
    +   */
    +  private static long[] convertToUnsafeRow(Row javaRow, StructType schema) {
    +    final UnsafeRowConverter converter = new UnsafeRowConverter(schema);
    +    final long[] unsafeRow = new long[converter.getSizeRequirement(javaRow)];
    +    final long writtenLength =
    +      converter.writeRow(javaRow, unsafeRow, PlatformDependent.LONG_ARRAY_OFFSET);
    +    assert (writtenLength == unsafeRow.length): "Size requirement calculation was wrong!";
    +    return unsafeRow;
    +  }
    +
    +  /**
    +   * Return the aggregation buffer for the current group. For efficiency, all calls to this method
    +   * return the same object.
    +   */
    +  public UnsafeRow getAggregationBuffer(Row groupingKey) {
    +    // Zero out the buffer that's used to hold the current row. This is necessary in order
    +    // to ensure that rows hash properly, since garbage data from the previous row could
    +    // otherwise end up as padding in this row.
    +    Arrays.fill(groupingKeyConversionScratchSpace, 0);
    --- End diff --
    
    technically we only need to zero out the beginning, no?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97340590
  
      [Test build #31245 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31245/consoleFull) for   PR 5725 at commit [`eeee512`](https://github.com/apache/spark/commit/eeee512bd94d463f741170e904ae186e238f997c).
     * This patch **passes all tests**.
     * This patch merges cleanly.
     * This patch adds the following public classes _(experimental)_:
      * `public final class UnsafeFixedWidthAggregationMap `
      * `  public static class MapEntry `
      * `public final class UnsafeRow implements MutableRow `
      * `class UnsafeRowConverter(fieldTypes: Array[DataType]) `
      * `public final class PlatformDependent `
      * `public class ByteArrayMethods `
      * `public final class LongArray `
      * `public final class BitSet `
      * `public final class BitSetMethods `
      * `public final class Murmur3_x86_32 `
      * `public final class BytesToBytesMap `
      * `  public final class Location `
      * `  class Doubling implements HashMapGrowthStrategy `
      * `public class ExecutorMemoryManager `
      * `public class HeapMemoryAllocator implements MemoryAllocator `
      * `public class MemoryBlock extends MemoryLocation `
      * `public class MemoryLocation `
      * `public final class TaskMemoryManager `
      * `public class UnsafeMemoryAllocator implements MemoryAllocator `
    
     * This patch **adds the following new dependencies:**
       * `spark-unsafe_2.10-1.4.0-SNAPSHOT.jar`



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97340658
  
    Merged build finished. Test PASSed.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by marmbrus <gi...@git.apache.org>.
Github user marmbrus commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29301384
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -41,13 +42,15 @@ case class AggregateEvaluation(
      * @param groupingExpressions expressions that are evaluated to determine grouping.
      * @param aggregateExpressions expressions that are computed for each group.
      * @param child the input data source.
    + * @param unsafeEnabled whether to allow Unsafe-based aggregation buffers to be used.
      */
     @DeveloperApi
     case class GeneratedAggregate(
    --- End diff --
    
    We should consider breaking this into two operators at some point so the explain is more readable.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29295786
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/TaskMemoryManager.java ---
    @@ -0,0 +1,237 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.*;
    +
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +/**
    + * Manages the memory allocated by an individual task.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    + * numbers are used to index into a "page table" array inside of the MemoryManager in order to
    + * retrieve the base object.
    + * <p>
    + * This allows us to address 8192 pages. In on-heap mode, the maximum page size is limited by the
    + * maximum size of a long[] array, allowing us to address 8192 * 2^32 * 8 bytes, which is
    + * approximately 35 terabytes of memory.
    + */
    +public final class TaskMemoryManager {
    +
    +  private final Logger logger = LoggerFactory.getLogger(TaskMemoryManager.class);
    +
    +  /**
    +   * The number of entries in the page table.
    +   */
    +  private static final int PAGE_TABLE_SIZE = 1 << 13;
    +
    +  /** Bit mask for the lower 51 bits of a long. */
    +  private static final long MASK_LONG_LOWER_51_BITS = 0x7FFFFFFFFFFFFL;
    +
    +  /** Bit mask for the upper 13 bits of a long */
    +  private static final long MASK_LONG_UPPER_13_BITS = ~MASK_LONG_LOWER_51_BITS;
    +
    +  /**
    +   * Similar to an operating system's page table, this array maps page numbers into base object
    +   * pointers, allowing us to translate between the hashtable's internal 64-bit address
    +   * representation and the baseObject+offset representation which we use to support both in- and
    +   * off-heap addresses. When using an off-heap allocator, every entry in this map will be `null`.
    +   * When using an in-heap allocator, the entries in this map will point to pages' base objects.
    +   * Entries are added to this map as new data pages are allocated.
    +   */
    +  private final MemoryBlock[] pageTable = new MemoryBlock[PAGE_TABLE_SIZE];
    +
    +  /**
    +   * Bitmap for tracking free pages.
    +   */
    +  private final BitSet allocatedPages = new BitSet(PAGE_TABLE_SIZE);
    +
    +  /**
    +   * Tracks memory allocated with {@link TaskMemoryManager#allocate(long)}, used to detect / clean
    +   * up leaked memory.
    +   */
    +  private final HashSet<MemoryBlock> allocatedNonPageMemory = new HashSet<MemoryBlock>();
    --- End diff --
    
    Here, I've used a HashSet to track non-page allocations.  I don't think that this should be _too_ expensive because we only use these in a couple of places (long arrays and bitsets, which we might just want to always keep on-heap anyways (in which case we don't need to involve the allocator)).  I didn't implement equals() or hashCode() for MemoryBlock, but I think that should be okay; object identity is fine for our purposes here.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29267226
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryManager.java ---
    @@ -0,0 +1,176 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.BitSet;
    +
    +/**
    + * Manages the lifecycle of data pages exchanged between operators.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    + * numbers are used to index into a "page table" array inside of the MemoryManager in order to
    + * retrieve the base object.
    + */
    +public final class MemoryManager {
    +
    +  /**
    +   * The number of entries in the page table.
    +   */
    +  private static final int PAGE_TABLE_SIZE = (int) 1L << 13;
    +
    +  /** Bit mask for the lower 51 bits of a long. */
    +  private static final long MASK_LONG_LOWER_51_BITS = 0x7FFFFFFFFFFFFL;
    +
    +  /** Bit mask for the upper 13 bits of a long */
    +  private static final long MASK_LONG_UPPER_13_BITS = ~MASK_LONG_LOWER_51_BITS;
    +
    +  /**
    +   * Similar to an operating system's page table, this array maps page numbers into base object
    +   * pointers, allowing us to translate between the hashtable's internal 64-bit address
    +   * representation and the baseObject+offset representation which we use to support both in- and
    +   * off-heap addresses. When using an off-heap allocator, every entry in this map will be `null`.
    +   * When using an in-heap allocator, the entries in this map will point to pages' base objects.
    +   * Entries are added to this map as new data pages are allocated.
    +   */
    +  private final MemoryBlock[] pageTable = new MemoryBlock[PAGE_TABLE_SIZE];
    +
    +  /**
    +   * Bitmap for tracking free pages.
    +   */
    +  private final BitSet allocatedPages = new BitSet(PAGE_TABLE_SIZE);
    +
    +  /**
    +   * Allocator, exposed for enabling untracked allocations of temporary data structures.
    +   */
    +  public final MemoryAllocator allocator;
    +
    +  /**
    +   * Tracks whether we're in-heap or off-heap. For off-heap, we short-circuit most of these methods
    +   * without doing any masking or lookups. Since this branching should be well-predicted by the JIT,
    +   * this extra layer of indirection / abstraction hopefully shouldn't be too expensive.
    +   */
    +  private final boolean inHeap;
    +
    +  /**
    +   * Construct a new MemoryManager.
    +   */
    +  public MemoryManager(MemoryAllocator allocator) {
    +    this.inHeap = allocator instanceof HeapMemoryAllocator;
    +    this.allocator = allocator;
    +  }
    +
    +  /**
    +   * Allocate a block of memory that will be tracked in the MemoryManager's page table; this is
    +   * intended for allocating large blocks of memory that will be shared between operators.
    +   */
    +  public MemoryBlock allocatePage(long size) {
    --- End diff --
    
    Agreed.  This package currently has no dependencies on `core`, so we can't use the `Logging` trait here.  Should we use the lower-level logging library directly, or just add the core dependency?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by asfgit <gi...@git.apache.org>.
Github user asfgit closed the pull request at:

    https://github.com/apache/spark/pull/5725


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29269271
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryManager.java ---
    @@ -0,0 +1,176 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.BitSet;
    +
    +/**
    + * Manages the lifecycle of data pages exchanged between operators.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    + * numbers are used to index into a "page table" array inside of the MemoryManager in order to
    + * retrieve the base object.
    + */
    +public final class MemoryManager {
    +
    +  /**
    +   * The number of entries in the page table.
    +   */
    +  private static final int PAGE_TABLE_SIZE = (int) 1L << 13;
    +
    +  /** Bit mask for the lower 51 bits of a long. */
    +  private static final long MASK_LONG_LOWER_51_BITS = 0x7FFFFFFFFFFFFL;
    +
    +  /** Bit mask for the upper 13 bits of a long */
    +  private static final long MASK_LONG_UPPER_13_BITS = ~MASK_LONG_LOWER_51_BITS;
    +
    +  /**
    +   * Similar to an operating system's page table, this array maps page numbers into base object
    +   * pointers, allowing us to translate between the hashtable's internal 64-bit address
    +   * representation and the baseObject+offset representation which we use to support both in- and
    +   * off-heap addresses. When using an off-heap allocator, every entry in this map will be `null`.
    +   * When using an in-heap allocator, the entries in this map will point to pages' base objects.
    +   * Entries are added to this map as new data pages are allocated.
    +   */
    +  private final MemoryBlock[] pageTable = new MemoryBlock[PAGE_TABLE_SIZE];
    +
    +  /**
    +   * Bitmap for tracking free pages.
    +   */
    +  private final BitSet allocatedPages = new BitSet(PAGE_TABLE_SIZE);
    +
    +  /**
    +   * Allocator, exposed for enabling untracked allocations of temporary data structures.
    +   */
    +  public final MemoryAllocator allocator;
    +
    +  /**
    +   * Tracks whether we're in-heap or off-heap. For off-heap, we short-circuit most of these methods
    +   * without doing any masking or lookups. Since this branching should be well-predicted by the JIT,
    +   * this extra layer of indirection / abstraction hopefully shouldn't be too expensive.
    +   */
    +  private final boolean inHeap;
    +
    +  /**
    +   * Construct a new MemoryManager.
    +   */
    +  public MemoryManager(MemoryAllocator allocator) {
    +    this.inHeap = allocator instanceof HeapMemoryAllocator;
    +    this.allocator = allocator;
    +  }
    +
    +  /**
    +   * Allocate a block of memory that will be tracked in the MemoryManager's page table; this is
    +   * intended for allocating large blocks of memory that will be shared between operators.
    +   */
    +  public MemoryBlock allocatePage(long size) {
    --- End diff --
    
    We can use the lower level logging library directly, like what the network module does.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by marmbrus <gi...@git.apache.org>.
Github user marmbrus commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29301331
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -265,7 +283,49 @@ case class GeneratedAggregate(
     
             val resultProjection = resultProjectionBuilder()
             Iterator(resultProjection(buffer))
    +      } else if (unsafeEnabled && schemaSupportsUnsafe) {
    +        log.info("Using Unsafe-based aggregator")
    +        val aggregationMap = new UnsafeFixedWidthAggregationMap(
    +          newAggregationBuffer(EmptyRow),
    +          aggregationBufferSchema,
    +          groupKeySchema,
    +          TaskContext.get.taskMemoryManager(),
    +          1024 * 16, // initial capacity
    +          false // disable tracking of performance metrics
    --- End diff --
    
    nit: consider named arguments instead of comments.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29284519
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryBlock.java ---
    @@ -0,0 +1,74 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import javax.annotation.Nullable;
    +
    +import org.apache.spark.unsafe.PlatformDependent;
    +
    +/**
    + * A consecutive block of memory, starting at a {@link MemoryLocation} with a fixed size.
    + */
    +public class MemoryBlock extends MemoryLocation {
    +
    +  private final long length;
    +
    +  /**
    +   * Optional page number; used when this MemoryBlock represents a page allocated by a
    +   * MemoryManager. This is package-private and is modified by MemoryManager.
    +   */
    +  int pageNumber = -1;
    --- End diff --
    
    My original motivation for making this an int was the fact that our page table is indexed by an integer, but now that I look more closely it looks like it's most-often read by `encodePageNumberAndOffset`, which does the long cast.  If we wanted to go a bit further in terms of saving instructions here, I guess we could store the pre-shifted page number then do the reverse shift for the accesses in `freePage`, since that's performed far fewer times.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29301701
  
    --- Diff: sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/UnsafeRowConverter.scala ---
    @@ -0,0 +1,226 @@
    +/*
    + * 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.spark.sql.catalyst.expressions
    +
    +import org.apache.spark.sql.types._
    +import org.apache.spark.unsafe.PlatformDependent
    +import org.apache.spark.unsafe.array.ByteArrayMethods
    +
    +/**
    + * Converts Rows into UnsafeRow format. This class is NOT thread-safe.
    + *
    + * @param fieldTypes the data types of the row's columns.
    + */
    +class UnsafeRowConverter(fieldTypes: Array[DataType]) {
    +
    +  def this(schema: StructType) {
    +    this(schema.fields.map(_.dataType))
    +  }
    +
    +  /** Re-used pointer to the unsafe row being written */
    +  private[this] val unsafeRow = new UnsafeRow()
    +
    +  /** Functions for encoding each column */
    +  private[this] val writers: Array[UnsafeColumnWriter[Any]] = {
    +    fieldTypes.map(t => UnsafeColumnWriter.forType(t).asInstanceOf[UnsafeColumnWriter[Any]])
    +  }
    +
    +  /** The size, in bytes, of the fixed-length portion of the row, including the null bitmap */
    +  private[this] val fixedLengthSize: Int =
    +    (8 * fieldTypes.length) + UnsafeRow.calculateBitSetWidthInBytes(fieldTypes.length)
    +
    +  /**
    +   * Compute the amount of space, in bytes, required to encode the given row.
    +   */
    +  def getSizeRequirement(row: Row): Int = {
    +    var fieldNumber = 0
    +    var variableLengthFieldSize: Int = 0
    +    while (fieldNumber < writers.length) {
    +      if (!row.isNullAt(fieldNumber)) {
    +        variableLengthFieldSize += writers(fieldNumber).getSize(row(fieldNumber))
    +      }
    +      fieldNumber += 1
    +    }
    +    fixedLengthSize + variableLengthFieldSize
    +  }
    +
    +  /**
    +   * Convert the given row into UnsafeRow format.
    +   *
    +   * @param row the row to convert
    +   * @param baseObject the base object of the destination address
    +   * @param baseOffset the base offset of the destination address
    +   * @return the number of bytes written. This should be equal to `getSizeRequirement(row)`.
    +   */
    +  def writeRow(row: Row, baseObject: Object, baseOffset: Long): Long = {
    +    unsafeRow.pointTo(baseObject, baseOffset, writers.length, null)
    +    var fieldNumber = 0
    +    var appendCursor: Int = fixedLengthSize
    +    while (fieldNumber < writers.length) {
    +      if (row.isNullAt(fieldNumber)) {
    +        unsafeRow.setNullAt(fieldNumber)
    +      } else {
    +        appendCursor += writers(fieldNumber).write(
    +          row(fieldNumber),
    --- End diff --
    
    That's a really good idea; can't believe I didn't think of that...
    
    Should be an easy change, so I'll do this shortly.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96962860
  
      [Test build #31113 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31113/consoleFull) for   PR 5725 at commit [`162caf7`](https://github.com/apache/spark/commit/162caf74c15952f6ae0482c1fa74529a0289b039).
     * This patch **passes all tests**.
     * This patch merges cleanly.
     * This patch adds the following public classes _(experimental)_:
      * `public final class UnsafeFixedWidthAggregationMap `
      * `  public static class MapEntry `
      * `public final class UnsafeRow implements MutableRow `
      * `class UnsafeRowConverter(fieldTypes: Array[DataType]) `
      * `public final class PlatformDependent `
      * `public class ByteArrayMethods `
      * `public final class LongArray `
      * `public final class BitSet `
      * `public final class BitSetMethods `
      * `public final class Murmur3_x86_32 `
      * `public final class BytesToBytesMap `
      * `  public final class Location `
      * `  class Doubling implements HashMapGrowthStrategy `
      * `public class HeapMemoryAllocator implements MemoryAllocator `
      * `public class MemoryBlock extends MemoryLocation `
      * `public class MemoryLocation `
      * `public final class MemoryManager `
      * `public class UnsafeMemoryAllocator implements MemoryAllocator `
    
     * This patch **adds the following new dependencies:**
       * `spark-unsafe_2.10-1.4.0-SNAPSHOT.jar`



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97281092
  
      [Test build #31202 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31202/consoleFull) for   PR 5725 at commit [`eeee512`](https://github.com/apache/spark/commit/eeee512bd94d463f741170e904ae186e238f997c).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29274142
  
    --- Diff: sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/UnsafeRowConverter.scala ---
    @@ -0,0 +1,226 @@
    +/*
    + * 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.spark.sql.catalyst.expressions
    +
    +import org.apache.spark.sql.types._
    +import org.apache.spark.unsafe.PlatformDependent
    +import org.apache.spark.unsafe.array.ByteArrayMethods
    +
    +/**
    + * Converts Rows into UnsafeRow format. This class is NOT thread-safe.
    + *
    + * @param fieldTypes the data types of the row's columns.
    + */
    +class UnsafeRowConverter(fieldTypes: Array[DataType]) {
    +
    +  def this(schema: StructType) {
    +    this(schema.fields.map(_.dataType))
    +  }
    +
    +  /** Re-used pointer to the unsafe row being written */
    +  private[this] val unsafeRow = new UnsafeRow()
    +
    +  /** Functions for encoding each column */
    +  private[this] val writers: Array[UnsafeColumnWriter[Any]] = {
    +    fieldTypes.map(t => UnsafeColumnWriter.forType(t).asInstanceOf[UnsafeColumnWriter[Any]])
    +  }
    +
    +  /** The size, in bytes, of the fixed-length portion of the row, including the null bitmap */
    +  private[this] val fixedLengthSize: Int =
    +    (8 * fieldTypes.length) + UnsafeRow.calculateBitSetWidthInBytes(fieldTypes.length)
    +
    +  /**
    +   * Compute the amount of space, in bytes, required to encode the given row.
    +   */
    +  def getSizeRequirement(row: Row): Int = {
    +    var fieldNumber = 0
    +    var variableLengthFieldSize: Int = 0
    +    while (fieldNumber < writers.length) {
    +      if (!row.isNullAt(fieldNumber)) {
    +        variableLengthFieldSize += writers(fieldNumber).getSize(row(fieldNumber))
    +      }
    +      fieldNumber += 1
    +    }
    +    fixedLengthSize + variableLengthFieldSize
    +  }
    +
    +  /**
    +   * Convert the given row into UnsafeRow format.
    +   *
    +   * @param row the row to convert
    +   * @param baseObject the base object of the destination address
    +   * @param baseOffset the base offset of the destination address
    +   * @return the number of bytes written. This should be equal to `getSizeRequirement(row)`.
    +   */
    +  def writeRow(row: Row, baseObject: Object, baseOffset: Long): Long = {
    +    unsafeRow.pointTo(baseObject, baseOffset, writers.length, null)
    +    var fieldNumber = 0
    +    var appendCursor: Int = fixedLengthSize
    +    while (fieldNumber < writers.length) {
    +      if (row.isNullAt(fieldNumber)) {
    +        unsafeRow.setNullAt(fieldNumber)
    +      } else {
    +        appendCursor += writers(fieldNumber).write(
    +          row(fieldNumber),
    +          fieldNumber,
    +          unsafeRow,
    +          baseObject,
    +          baseOffset,
    +          appendCursor)
    +      }
    +      fieldNumber += 1
    +    }
    +    appendCursor
    +  }
    +
    +}
    +
    +/**
    + * Function for writing a column into an UnsafeRow.
    + */
    +private abstract class UnsafeColumnWriter[T] {
    +  /**
    +   * Write a value into an UnsafeRow.
    +   *
    +   * @param value the value to write
    +   * @param columnNumber what column to write it to
    +   * @param row a pointer to the unsafe row
    +   * @param baseObject the base object of the target row's address
    +   * @param baseOffset the base offset of the target row's address
    +   * @param appendCursor the offset from the start of the unsafe row to the end of the row;
    +   *                     used for calculating where variable-length data should be written
    +   * @return the number of variable-length bytes written
    +   */
    +  def write(
    +      value: T,
    +      columnNumber: Int,
    +      row: UnsafeRow,
    +      baseObject: Object,
    +      baseOffset: Long,
    +      appendCursor: Int): Int
    +
    +  /**
    +   * Return the number of bytes that are needed to write this variable-length value.
    +   */
    +  def getSize(value: T): Int
    +}
    +
    +private object UnsafeColumnWriter {
    +
    +  def forType(dataType: DataType): UnsafeColumnWriter[_] = {
    +    dataType match {
    +      case IntegerType => IntUnsafeColumnWriter
    +      case LongType => LongUnsafeColumnWriter
    +      case FloatType => FloatUnsafeColumnWriter
    +      case DoubleType => DoubleUnsafeColumnWriter
    +      case StringType => StringUnsafeColumnWriter
    +      case t =>
    +        throw new UnsupportedOperationException(s"Do not know how to write columns of type $t")
    +    }
    +  }
    +}
    +
    +// ------------------------------------------------------------------------------------------------
    +
    +private object IntUnsafeColumnWriter extends IntUnsafeColumnWriter
    +private object LongUnsafeColumnWriter extends LongUnsafeColumnWriter
    +private object FloatUnsafeColumnWriter extends FloatUnsafeColumnWriter
    +private object DoubleUnsafeColumnWriter extends DoubleUnsafeColumnWriter
    +private object StringUnsafeColumnWriter extends StringUnsafeColumnWriter
    +
    +private abstract class PrimitiveUnsafeColumnWriter[T] extends UnsafeColumnWriter[T] {
    +  def getSize(value: T): Int = 0
    +}
    +
    +private class IntUnsafeColumnWriter private() extends PrimitiveUnsafeColumnWriter[Int] {
    +  override def write(
    --- End diff --
    
    More specifically, this is the number of variable-length bytes written.  Primitive types, like int, don't write to the variable-length portion and thus return 0.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by vanzin <gi...@git.apache.org>.
Github user vanzin commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97905259
  
    On a side note, if Spark supports java 6, why are all jenkins builds running java 7?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96774641
  
      [Test build #31059 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31059/consoleFull) for   PR 5725 at commit [`cde4132`](https://github.com/apache/spark/commit/cde413249c0083f175843b3d25023a76948692b2).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29221679
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryManager.java ---
    @@ -0,0 +1,176 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.BitSet;
    +
    +/**
    + * Manages the lifecycle of data pages exchanged between operators.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    + * numbers are used to index into a "page table" array inside of the MemoryManager in order to
    + * retrieve the base object.
    + */
    +public final class MemoryManager {
    +
    +  /**
    +   * The number of entries in the page table.
    +   */
    +  private static final int PAGE_TABLE_SIZE = (int) 1L << 13;
    +
    +  /** Bit mask for the lower 51 bits of a long. */
    +  private static final long MASK_LONG_LOWER_51_BITS = 0x7FFFFFFFFFFFFL;
    +
    +  /** Bit mask for the upper 13 bits of a long */
    +  private static final long MASK_LONG_UPPER_13_BITS = ~MASK_LONG_LOWER_51_BITS;
    +
    +  /**
    +   * Similar to an operating system's page table, this array maps page numbers into base object
    +   * pointers, allowing us to translate between the hashtable's internal 64-bit address
    +   * representation and the baseObject+offset representation which we use to support both in- and
    +   * off-heap addresses. When using an off-heap allocator, every entry in this map will be `null`.
    +   * When using an in-heap allocator, the entries in this map will point to pages' base objects.
    +   * Entries are added to this map as new data pages are allocated.
    +   */
    +  private final MemoryBlock[] pageTable = new MemoryBlock[PAGE_TABLE_SIZE];
    +
    +  /**
    +   * Bitmap for tracking free pages.
    +   */
    +  private final BitSet allocatedPages = new BitSet(PAGE_TABLE_SIZE);
    +
    +  /**
    +   * Allocator, exposed for enabling untracked allocations of temporary data structures.
    +   */
    +  public final MemoryAllocator allocator;
    +
    +  /**
    +   * Tracks whether we're in-heap or off-heap. For off-heap, we short-circuit most of these methods
    +   * without doing any masking or lookups. Since this branching should be well-predicted by the JIT,
    +   * this extra layer of indirection / abstraction hopefully shouldn't be too expensive.
    +   */
    +  private final boolean inHeap;
    +
    +  /**
    +   * Construct a new MemoryManager.
    +   */
    +  public MemoryManager(MemoryAllocator allocator) {
    +    this.inHeap = allocator instanceof HeapMemoryAllocator;
    +    this.allocator = allocator;
    +  }
    +
    +  /**
    +   * Allocate a block of memory that will be tracked in the MemoryManager's page table; this is
    +   * intended for allocating large blocks of memory that will be shared between operators.
    +   */
    +  public MemoryBlock allocatePage(long size) {
    --- End diff --
    
    would be great to log something here


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96968405
  
    I went through and left some comments. Kudos - this is super well done!



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29274312
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryBlock.java ---
    @@ -0,0 +1,74 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import javax.annotation.Nullable;
    +
    +import org.apache.spark.unsafe.PlatformDependent;
    +
    +/**
    + * A consecutive block of memory, starting at a {@link MemoryLocation} with a fixed size.
    + */
    +public class MemoryBlock extends MemoryLocation {
    +
    +  private final long length;
    +
    +  /**
    +   * Optional page number; used when this MemoryBlock represents a page allocated by a
    +   * MemoryManager. This is package-private and is modified by MemoryManager.
    +   */
    +  int pageNumber = -1;
    +
    +  public int getPageNumber() {
    +    return pageNumber;
    +  }
    +
    +  MemoryBlock(@Nullable Object obj, long offset, long length) {
    +    super(obj, offset);
    +    this.length = length;
    +  }
    +
    +  /**
    +   * Returns the size of the memory block.
    +   */
    +  public long size() {
    +    return length;
    +  }
    +
    +  /**
    +   * Clear the contents of this memory block.  Returns `this` to facilitate chaining.
    +   */
    +  public MemoryBlock zero() {
    +    PlatformDependent.UNSAFE.setMemory(obj, offset, length, (byte) 0);
    +    return this;
    +  }
    +
    +  /**
    +   * Creates a memory block pointing to the memory used by the byte array.
    +   */
    +  public static MemoryBlock fromByteArray(final byte[] array) {
    --- End diff --
    
    It's called in a test method in `TestLongArray.scala`, but we don't need it.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97311123
  
    Jenkins, retest this please.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97203637
  
     Merged build triggered.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97311194
  
      [Test build #31245 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31245/consoleFull) for   PR 5725 at commit [`eeee512`](https://github.com/apache/spark/commit/eeee512bd94d463f741170e904ae186e238f997c).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97263417
  
    Test FAILed.
    Refer to this link for build results (access rights to CI server needed): 
    https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31173/
    Test FAILed.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96784215
  
      [Test build #31059 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31059/consoleFull) for   PR 5725 at commit [`cde4132`](https://github.com/apache/spark/commit/cde413249c0083f175843b3d25023a76948692b2).
     * This patch **fails MiMa tests**.
     * This patch merges cleanly.
     * This patch adds the following public classes _(experimental)_:
      * `public final class UnsafeFixedWidthAggregationMap `
      * `  public static class MapEntry `
      * `public final class UnsafeRow implements MutableRow `
      * `class UnsafeRowConverter(fieldTypes: Array[DataType]) `
      * `public final class PlatformDependent `
      * `public class ByteArrayMethods `
      * `public final class LongArray `
      * `public final class BitSet `
      * `public final class BitSetMethods `
      * `public final class Murmur3_x86_32 `
      * `public final class BytesToBytesMap `
      * `  public final class Location `
      * `  class Doubling implements HashMapGrowthStrategy `
      * `public class HeapMemoryAllocator implements MemoryAllocator `
      * `public class MemoryBlock extends MemoryLocation `
      * `public class MemoryLocation `
      * `public class UnsafeMemoryAllocator implements MemoryAllocator `
    
     * This patch **adds the following new dependencies:**
       * `spark-unsafe_2.10-1.4.0-SNAPSHOT.jar`
       * `tachyon-0.6.4.jar`
       * `tachyon-client-0.6.4.jar`
    
     * This patch **removes the following dependencies:**
       * `tachyon-0.5.0.jar`
       * `tachyon-client-0.5.0.jar`



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97284007
  
    Test FAILed.
    Refer to this link for build results (access rights to CI server needed): 
    https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31202/
    Test FAILed.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97203679
  
    Merged build started.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29287008
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryManager.java ---
    @@ -0,0 +1,176 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.BitSet;
    +
    +/**
    + * Manages the lifecycle of data pages exchanged between operators.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    + * numbers are used to index into a "page table" array inside of the MemoryManager in order to
    + * retrieve the base object.
    + */
    +public final class MemoryManager {
    +
    +  /**
    +   * The number of entries in the page table.
    +   */
    +  private static final int PAGE_TABLE_SIZE = (int) 1L << 13;
    +
    +  /** Bit mask for the lower 51 bits of a long. */
    +  private static final long MASK_LONG_LOWER_51_BITS = 0x7FFFFFFFFFFFFL;
    +
    +  /** Bit mask for the upper 13 bits of a long */
    +  private static final long MASK_LONG_UPPER_13_BITS = ~MASK_LONG_LOWER_51_BITS;
    +
    +  /**
    +   * Similar to an operating system's page table, this array maps page numbers into base object
    +   * pointers, allowing us to translate between the hashtable's internal 64-bit address
    +   * representation and the baseObject+offset representation which we use to support both in- and
    +   * off-heap addresses. When using an off-heap allocator, every entry in this map will be `null`.
    +   * When using an in-heap allocator, the entries in this map will point to pages' base objects.
    +   * Entries are added to this map as new data pages are allocated.
    +   */
    +  private final MemoryBlock[] pageTable = new MemoryBlock[PAGE_TABLE_SIZE];
    +
    +  /**
    +   * Bitmap for tracking free pages.
    +   */
    +  private final BitSet allocatedPages = new BitSet(PAGE_TABLE_SIZE);
    +
    +  /**
    +   * Allocator, exposed for enabling untracked allocations of temporary data structures.
    +   */
    +  public final MemoryAllocator allocator;
    +
    +  /**
    +   * Tracks whether we're in-heap or off-heap. For off-heap, we short-circuit most of these methods
    +   * without doing any masking or lookups. Since this branching should be well-predicted by the JIT,
    +   * this extra layer of indirection / abstraction hopefully shouldn't be too expensive.
    +   */
    +  private final boolean inHeap;
    +
    +  /**
    +   * Construct a new MemoryManager.
    +   */
    +  public MemoryManager(MemoryAllocator allocator) {
    +    this.inHeap = allocator instanceof HeapMemoryAllocator;
    +    this.allocator = allocator;
    +  }
    +
    +  /**
    +   * Allocate a block of memory that will be tracked in the MemoryManager's page table; this is
    +   * intended for allocating large blocks of memory that will be shared between operators.
    +   */
    +  public MemoryBlock allocatePage(long size) {
    +    if (size >= (1L << 51)) {
    +      throw new IllegalArgumentException("Cannot allocate a page with more than 2^51 bytes");
    +    }
    +
    +    final int pageNumber;
    +    synchronized (this) {
    +      pageNumber = allocatedPages.nextClearBit(0);
    +      if (pageNumber >= PAGE_TABLE_SIZE) {
    +        throw new IllegalStateException(
    +          "Have already allocated a maximum of " + PAGE_TABLE_SIZE + " pages");
    +      }
    +      allocatedPages.set(pageNumber);
    +    }
    +    final MemoryBlock page = allocator.allocate(size);
    +    page.pageNumber = pageNumber;
    +    pageTable[pageNumber] = page;
    +    return page;
    +  }
    +
    +  /**
    +   * Free a block of memory allocated via {@link MemoryManager#allocatePage(long)}.
    +   */
    +  public void freePage(MemoryBlock page) {
    --- End diff --
    
    Done.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29216032
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeRow.java ---
    @@ -0,0 +1,428 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import scala.collection.Map;
    +import scala.collection.Seq;
    +import scala.collection.mutable.ArraySeq;
    +
    +import javax.annotation.Nullable;
    +import java.math.BigDecimal;
    +import java.sql.Date;
    +import java.util.*;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.DataType;
    +import static org.apache.spark.sql.types.DataTypes.*;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.sql.types.UTF8String;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.bitset.BitSetMethods;
    +
    +/**
    + * An Unsafe implementation of Row which is backed by raw memory instead of Java objects.
    + *
    + * Each tuple has three parts: [null bit set] [values] [variable length portion]
    + *
    + * The bit set is used for null tracking and is aligned to 8-byte word boundaries.  It stores
    + * one bit per field.
    + *
    + * In the `values` region, we store one 8-byte word per field. For fields that hold fixed-length
    + * primitive types, such as long, double, or int, we store the value directly in the word. For
    + * fields with non-primitive or variable-length values, we store a relative offset (w.r.t. the
    + * base address of the row) that points to the beginning of the variable-length field.
    + *
    + * Instances of `UnsafeRow` act as pointers to row data stored in this format, similar to how
    + * `Writable` objects work in Hadoop.
    + */
    +public final class UnsafeRow implements MutableRow {
    +
    +  private Object baseObject;
    +  private long baseOffset;
    +  /** The number of fields in this row, used for calculating the bitset width (and in assertions) */
    +  private int numFields;
    +  /** The width of the null tracking bit set, in bytes */
    +  private int bitSetWidthInBytes;
    +  /**
    +   * This optional schema is required if you want to call generic get() and set() methods on
    +   * this UnsafeRow, but is optional if callers will only use type-specific getTYPE() and setTYPE()
    +   * methods.
    +   */
    +  @Nullable
    +  private StructType schema;
    --- End diff --
    
    It's used in the generic `get()` call, which is only called internally by generated code that accesses UTF8String columns.  If we add an internal `getUTF8String()` method and update the code generator to use this, then we can completely remove this.  I might take a stab at this, since I think it's a pretty minimal change (I'll clearly mark the new method as internal so that it gets handled right during the planned InternalRow / Row split).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97883422
  
    Did you have warning turned on into error?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96888987
  
      [Test build #31095 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31095/consoleFull) for   PR 5725 at commit [`a8e4a3f`](https://github.com/apache/spark/commit/a8e4a3fe40574c3a609beeb4794b11bd720a31e7).
     * This patch **fails Spark unit tests**.
     * This patch merges cleanly.
     * This patch adds the following public classes _(experimental)_:
      * `public final class UnsafeFixedWidthAggregationMap `
      * `  public static class MapEntry `
      * `public final class UnsafeRow implements MutableRow `
      * `class UnsafeRowConverter(fieldTypes: Array[DataType]) `
      * `public final class PlatformDependent `
      * `public class ByteArrayMethods `
      * `public final class LongArray `
      * `public final class BitSet `
      * `public final class BitSetMethods `
      * `public final class Murmur3_x86_32 `
      * `public final class BytesToBytesMap `
      * `  public final class Location `
      * `  class Doubling implements HashMapGrowthStrategy `
      * `public class HeapMemoryAllocator implements MemoryAllocator `
      * `public class MemoryBlock extends MemoryLocation `
      * `public class MemoryLocation `
      * `public final class MemoryManager `
      * `public class UnsafeMemoryAllocator implements MemoryAllocator `
    
     * This patch **removes the following dependencies:**
       * `RoaringBitmap-0.4.5.jar`
       * `activation-1.1.jar`
       * `akka-actor_2.10-2.3.4-spark.jar`
       * `akka-remote_2.10-2.3.4-spark.jar`
       * `akka-slf4j_2.10-2.3.4-spark.jar`
       * `aopalliance-1.0.jar`
       * `arpack_combined_all-0.1.jar`
       * `avro-1.7.7.jar`
       * `breeze-macros_2.10-0.11.2.jar`
       * `breeze_2.10-0.11.2.jar`
       * `chill-java-0.5.0.jar`
       * `chill_2.10-0.5.0.jar`
       * `commons-beanutils-1.7.0.jar`
       * `commons-beanutils-core-1.8.0.jar`
       * `commons-cli-1.2.jar`
       * `commons-codec-1.10.jar`
       * `commons-collections-3.2.1.jar`
       * `commons-compress-1.4.1.jar`
       * `commons-configuration-1.6.jar`
       * `commons-digester-1.8.jar`
       * `commons-httpclient-3.1.jar`
       * `commons-io-2.1.jar`
       * `commons-lang-2.5.jar`
       * `commons-lang3-3.3.2.jar`
       * `commons-math-2.1.jar`
       * `commons-math3-3.4.1.jar`
       * `commons-net-2.2.jar`
       * `compress-lzf-1.0.0.jar`
       * `config-1.2.1.jar`
       * `core-1.1.2.jar`
       * `curator-client-2.4.0.jar`
       * `curator-framework-2.4.0.jar`
       * `curator-recipes-2.4.0.jar`
       * `gmbal-api-only-3.0.0-b023.jar`
       * `grizzly-framework-2.1.2.jar`
       * `grizzly-http-2.1.2.jar`
       * `grizzly-http-server-2.1.2.jar`
       * `grizzly-http-servlet-2.1.2.jar`
       * `grizzly-rcm-2.1.2.jar`
       * `groovy-all-2.3.7.jar`
       * `guava-14.0.1.jar`
       * `guice-3.0.jar`
       * `hadoop-annotations-2.2.0.jar`
       * `hadoop-auth-2.2.0.jar`
       * `hadoop-client-2.2.0.jar`
       * `hadoop-common-2.2.0.jar`
       * `hadoop-hdfs-2.2.0.jar`
       * `hadoop-mapreduce-client-app-2.2.0.jar`
       * `hadoop-mapreduce-client-common-2.2.0.jar`
       * `hadoop-mapreduce-client-core-2.2.0.jar`
       * `hadoop-mapreduce-client-jobclient-2.2.0.jar`
       * `hadoop-mapreduce-client-shuffle-2.2.0.jar`
       * `hadoop-yarn-api-2.2.0.jar`
       * `hadoop-yarn-client-2.2.0.jar`
       * `hadoop-yarn-common-2.2.0.jar`
       * `hadoop-yarn-server-common-2.2.0.jar`
       * `ivy-2.4.0.jar`
       * `jackson-annotations-2.4.0.jar`
       * `jackson-core-2.4.4.jar`
       * `jackson-core-asl-1.8.8.jar`
       * `jackson-databind-2.4.4.jar`
       * `jackson-jaxrs-1.8.8.jar`
       * `jackson-mapper-asl-1.8.8.jar`
       * `jackson-module-scala_2.10-2.4.4.jar`
       * `jackson-xc-1.8.8.jar`
       * `jansi-1.4.jar`
       * `javax.inject-1.jar`
       * `javax.servlet-3.0.0.v201112011016.jar`
       * `javax.servlet-3.1.jar`
       * `javax.servlet-api-3.0.1.jar`
       * `jaxb-api-2.2.2.jar`
       * `jaxb-impl-2.2.3-1.jar`
       * `jcl-over-slf4j-1.7.10.jar`
       * `jersey-client-1.9.jar`
       * `jersey-core-1.9.jar`
       * `jersey-grizzly2-1.9.jar`
       * `jersey-guice-1.9.jar`
       * `jersey-json-1.9.jar`
       * `jersey-server-1.9.jar`
       * `jersey-test-framework-core-1.9.jar`
       * `jersey-test-framework-grizzly2-1.9.jar`
       * `jets3t-0.7.1.jar`
       * `jettison-1.1.jar`
       * `jetty-util-6.1.26.jar`
       * `jline-0.9.94.jar`
       * `jline-2.10.4.jar`
       * `jodd-core-3.6.3.jar`
       * `json4s-ast_2.10-3.2.10.jar`
       * `json4s-core_2.10-3.2.10.jar`
       * `json4s-jackson_2.10-3.2.10.jar`
       * `jsr305-1.3.9.jar`
       * `jtransforms-2.4.0.jar`
       * `jul-to-slf4j-1.7.10.jar`
       * `kryo-2.21.jar`
       * `log4j-1.2.17.jar`
       * `lz4-1.2.0.jar`
       * `management-api-3.0.0-b012.jar`
       * `mesos-0.21.0-shaded-protobuf.jar`
       * `metrics-core-3.1.0.jar`
       * `metrics-graphite-3.1.0.jar`
       * `metrics-json-3.1.0.jar`
       * `metrics-jvm-3.1.0.jar`
       * `minlog-1.2.jar`
       * `netty-3.8.0.Final.jar`
       * `netty-all-4.0.23.Final.jar`
       * `objenesis-1.2.jar`
       * `opencsv-2.3.jar`
       * `oro-2.0.8.jar`
       * `paranamer-2.6.jar`
       * `parquet-column-1.6.0rc3.jar`
       * `parquet-common-1.6.0rc3.jar`
       * `parquet-encoding-1.6.0rc3.jar`
       * `parquet-format-2.2.0-rc1.jar`
       * `parquet-generator-1.6.0rc3.jar`
       * `parquet-hadoop-1.6.0rc3.jar`
       * `parquet-jackson-1.6.0rc3.jar`
       * `protobuf-java-2.4.1.jar`
       * `protobuf-java-2.5.0-spark.jar`
       * `py4j-0.8.2.1.jar`
       * `pyrolite-2.0.1.jar`
       * `quasiquotes_2.10-2.0.1.jar`
       * `reflectasm-1.07-shaded.jar`
       * `scala-compiler-2.10.4.jar`
       * `scala-library-2.10.4.jar`
       * `scala-reflect-2.10.4.jar`
       * `scalap-2.10.4.jar`
       * `scalatest_2.10-2.2.1.jar`
       * `slf4j-api-1.7.10.jar`
       * `slf4j-log4j12-1.7.10.jar`
       * `snappy-java-1.1.1.7.jar`
       * `spark-bagel_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-catalyst_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-core_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-graphx_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-launcher_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-mllib_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-network-common_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-network-shuffle_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-repl_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-sql_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-streaming_2.10-1.4.0-SNAPSHOT.jar`
       * `spire-macros_2.10-0.7.4.jar`
       * `spire_2.10-0.7.4.jar`
       * `stax-api-1.0.1.jar`
       * `stream-2.7.0.jar`
       * `tachyon-0.6.4.jar`
       * `tachyon-client-0.6.4.jar`
       * `uncommons-maths-1.2.2a.jar`
       * `unused-1.0.0.jar`
       * `xmlenc-0.52.jar`
       * `xz-1.0.jar`
       * `zookeeper-3.4.5.jar`



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29268634
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeRow.java ---
    @@ -0,0 +1,428 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import scala.collection.Map;
    +import scala.collection.Seq;
    +import scala.collection.mutable.ArraySeq;
    +
    +import javax.annotation.Nullable;
    +import java.math.BigDecimal;
    +import java.sql.Date;
    +import java.util.*;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.DataType;
    +import static org.apache.spark.sql.types.DataTypes.*;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.sql.types.UTF8String;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.bitset.BitSetMethods;
    +
    +/**
    + * An Unsafe implementation of Row which is backed by raw memory instead of Java objects.
    + *
    + * Each tuple has three parts: [null bit set] [values] [variable length portion]
    + *
    + * The bit set is used for null tracking and is aligned to 8-byte word boundaries.  It stores
    + * one bit per field.
    + *
    + * In the `values` region, we store one 8-byte word per field. For fields that hold fixed-length
    + * primitive types, such as long, double, or int, we store the value directly in the word. For
    + * fields with non-primitive or variable-length values, we store a relative offset (w.r.t. the
    + * base address of the row) that points to the beginning of the variable-length field.
    + *
    + * Instances of `UnsafeRow` act as pointers to row data stored in this format, similar to how
    + * `Writable` objects work in Hadoop.
    + */
    +public final class UnsafeRow implements MutableRow {
    +
    +  private Object baseObject;
    +  private long baseOffset;
    +  /** The number of fields in this row, used for calculating the bitset width (and in assertions) */
    +  private int numFields;
    +  /** The width of the null tracking bit set, in bytes */
    +  private int bitSetWidthInBytes;
    +  /**
    +   * This optional schema is required if you want to call generic get() and set() methods on
    +   * this UnsafeRow, but is optional if callers will only use type-specific getTYPE() and setTYPE()
    +   * methods.
    +   */
    +  @Nullable
    +  private StructType schema;
    +
    +  private long getFieldOffset(int ordinal) {
    +   return baseOffset + bitSetWidthInBytes + ordinal * 8L;
    +  }
    +
    +  public static int calculateBitSetWidthInBytes(int numFields) {
    +    return ((numFields / 64) + (numFields % 64 == 0 ? 0 : 1)) * 8;
    +  }
    +
    +  /**
    +   * Field types that can be updated in place in UnsafeRows (e.g. we support set() for these types)
    +   */
    +  public static final Set<DataType> settableFieldTypes;
    +
    +  /**
    +   * Fields types can be read(but not set (e.g. set() will throw UnsupportedOperationException).
    +   */
    +  public static final Set<DataType> readableFieldTypes;
    +
    +  static {
    +    settableFieldTypes = Collections.unmodifiableSet(
    +      new HashSet<DataType>(
    +        Arrays.asList(new DataType[] {
    --- End diff --
    
    Done: https://issues.apache.org/jira/browse/SPARK-7199


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29304001
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/SQLConf.scala ---
    @@ -30,6 +30,7 @@ private[spark] object SQLConf {
       val DEFAULT_SIZE_IN_BYTES = "spark.sql.defaultSizeInBytes"
       val SHUFFLE_PARTITIONS = "spark.sql.shuffle.partitions"
       val CODEGEN_ENABLED = "spark.sql.codegen"
    +  val UNSAFE_ENABLED = "spark.sql.unsafe.enabled"
    --- End diff --
    
    There was an option for choosing heap vs. offheap, but that option got moved into Spark core.  I think we use the `enabled` convention a bit more in core.  I don't have strong feelings on this one.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97284000
  
      [Test build #31202 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31202/consoleFull) for   PR 5725 at commit [`eeee512`](https://github.com/apache/spark/commit/eeee512bd94d463f741170e904ae186e238f997c).
     * This patch **fails MiMa tests**.
     * This patch merges cleanly.
     * This patch adds the following public classes _(experimental)_:
      * `public final class UnsafeFixedWidthAggregationMap `
      * `  public static class MapEntry `
      * `public final class UnsafeRow implements MutableRow `
      * `class UnsafeRowConverter(fieldTypes: Array[DataType]) `
      * `public final class PlatformDependent `
      * `public class ByteArrayMethods `
      * `public final class LongArray `
      * `public final class BitSet `
      * `public final class BitSetMethods `
      * `public final class Murmur3_x86_32 `
      * `public final class BytesToBytesMap `
      * `  public final class Location `
      * `  class Doubling implements HashMapGrowthStrategy `
      * `public class ExecutorMemoryManager `
      * `public class HeapMemoryAllocator implements MemoryAllocator `
      * `public class MemoryBlock extends MemoryLocation `
      * `public class MemoryLocation `
      * `public final class TaskMemoryManager `
      * `public class UnsafeMemoryAllocator implements MemoryAllocator `
    
     * This patch **adds the following new dependencies:**
       * `spark-unsafe_2.10-1.4.0-SNAPSHOT.jar`



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by tgravescs <gi...@git.apache.org>.
Github user tgravescs commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97899617
  
    Thanks, Also I should have specified, I'm running on a rhel6 box using jdlk6


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29220143
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeRow.java ---
    @@ -0,0 +1,428 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import scala.collection.Map;
    +import scala.collection.Seq;
    +import scala.collection.mutable.ArraySeq;
    +
    +import javax.annotation.Nullable;
    +import java.math.BigDecimal;
    +import java.sql.Date;
    +import java.util.*;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.DataType;
    +import static org.apache.spark.sql.types.DataTypes.*;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.sql.types.UTF8String;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.bitset.BitSetMethods;
    +
    +/**
    + * An Unsafe implementation of Row which is backed by raw memory instead of Java objects.
    + *
    + * Each tuple has three parts: [null bit set] [values] [variable length portion]
    + *
    + * The bit set is used for null tracking and is aligned to 8-byte word boundaries.  It stores
    + * one bit per field.
    + *
    + * In the `values` region, we store one 8-byte word per field. For fields that hold fixed-length
    + * primitive types, such as long, double, or int, we store the value directly in the word. For
    + * fields with non-primitive or variable-length values, we store a relative offset (w.r.t. the
    + * base address of the row) that points to the beginning of the variable-length field.
    + *
    + * Instances of `UnsafeRow` act as pointers to row data stored in this format, similar to how
    + * `Writable` objects work in Hadoop.
    + */
    +public final class UnsafeRow implements MutableRow {
    +
    +  private Object baseObject;
    +  private long baseOffset;
    +  /** The number of fields in this row, used for calculating the bitset width (and in assertions) */
    +  private int numFields;
    +  /** The width of the null tracking bit set, in bytes */
    +  private int bitSetWidthInBytes;
    +  /**
    +   * This optional schema is required if you want to call generic get() and set() methods on
    +   * this UnsafeRow, but is optional if callers will only use type-specific getTYPE() and setTYPE()
    +   * methods.
    +   */
    +  @Nullable
    +  private StructType schema;
    +
    +  private long getFieldOffset(int ordinal) {
    +   return baseOffset + bitSetWidthInBytes + ordinal * 8L;
    +  }
    +
    +  public static int calculateBitSetWidthInBytes(int numFields) {
    +    return ((numFields / 64) + (numFields % 64 == 0 ? 0 : 1)) * 8;
    +  }
    +
    +  /**
    +   * Field types that can be updated in place in UnsafeRows (e.g. we support set() for these types)
    +   */
    +  public static final Set<DataType> settableFieldTypes;
    +
    +  /**
    +   * Fields types can be read(but not set (e.g. set() will throw UnsupportedOperationException).
    +   */
    +  public static final Set<DataType> readableFieldTypes;
    +
    +  static {
    +    settableFieldTypes = Collections.unmodifiableSet(
    +      new HashSet<DataType>(
    +        Arrays.asList(new DataType[] {
    +          IntegerType,
    +          LongType,
    +          DoubleType,
    +          BooleanType,
    +          ShortType,
    +          ByteType,
    +          FloatType
    +    })));
    +
    +    // We support get() on a superset of the types for which we support set():
    +    final Set<DataType> _readableFieldTypes = new HashSet<DataType>(
    +      Arrays.asList(new DataType[]{
    +        StringType
    +      }));
    +    _readableFieldTypes.addAll(settableFieldTypes);
    +    readableFieldTypes = Collections.unmodifiableSet(_readableFieldTypes);
    +  }
    +
    +  /**
    +   * Construct a new UnsafeRow. The resulting row won't be usable until `pointTo()` has been called,
    +   * since the value returned by this constructor is equivalent to a null pointer.
    +   */
    +  public UnsafeRow() { }
    +
    +  /**
    +   * Update this UnsafeRow to point to different backing data.
    +   *
    +   * @param baseObject the base object
    +   * @param baseOffset the offset within the base object
    +   * @param numFields the number of fields in this row
    +   * @param schema an optional schema; this is necessary if you want to call generic get() or set()
    +   *               methods on this row, but is optional if the caller will only use type-specific
    +   *               getTYPE() and setTYPE() methods.
    +   */
    +  public void pointTo(
    +      Object baseObject,
    +      long baseOffset,
    +      int numFields,
    +      @Nullable StructType schema) {
    +    assert numFields >= 0 : "numFields should >= 0";
    +    assert schema == null || schema.fields().length == numFields;
    +    this.bitSetWidthInBytes = calculateBitSetWidthInBytes(numFields);
    +    this.baseObject = baseObject;
    +    this.baseOffset = baseOffset;
    +    this.numFields = numFields;
    +    this.schema = schema;
    +  }
    +
    +  private void assertIndexIsValid(int index) {
    +    assert index >= 0 : "index (" + index + ") should >= 0";
    +    assert index < numFields : "index (" + index + ") should <= " + numFields;
    +  }
    +
    +  @Override
    +  public void setNullAt(int i) {
    +    assertIndexIsValid(i);
    +    BitSetMethods.set(baseObject, baseOffset, i);
    +    // To preserve row equality, zero out the value when setting the column to null.
    +    // Since this row does does not currently support updates to variable-length values, we don't
    +    // have to worry about zeroing out that data.
    +    PlatformDependent.UNSAFE.putLong(baseObject, getFieldOffset(i), 0);
    +  }
    +
    +  private void setNotNullAt(int i) {
    +    assertIndexIsValid(i);
    +    BitSetMethods.unset(baseObject, baseOffset, i);
    +  }
    +
    +  @Override
    +  public void update(int ordinal, Object value) {
    +    throw new UnsupportedOperationException();
    +  }
    +
    +  @Override
    +  public void setInt(int ordinal, int value) {
    +    assertIndexIsValid(ordinal);
    +    setNotNullAt(ordinal);
    +    PlatformDependent.UNSAFE.putInt(baseObject, getFieldOffset(ordinal), value);
    +  }
    +
    +  @Override
    +  public void setLong(int ordinal, long value) {
    +    assertIndexIsValid(ordinal);
    +    setNotNullAt(ordinal);
    +    PlatformDependent.UNSAFE.putLong(baseObject, getFieldOffset(ordinal), value);
    +  }
    +
    +  @Override
    +  public void setDouble(int ordinal, double value) {
    +    assertIndexIsValid(ordinal);
    +    setNotNullAt(ordinal);
    +    PlatformDependent.UNSAFE.putDouble(baseObject, getFieldOffset(ordinal), value);
    +  }
    +
    +  @Override
    +  public void setBoolean(int ordinal, boolean value) {
    +    assertIndexIsValid(ordinal);
    +    setNotNullAt(ordinal);
    +    PlatformDependent.UNSAFE.putBoolean(baseObject, getFieldOffset(ordinal), value);
    +  }
    +
    +  @Override
    +  public void setShort(int ordinal, short value) {
    +    assertIndexIsValid(ordinal);
    +    setNotNullAt(ordinal);
    +    PlatformDependent.UNSAFE.putShort(baseObject, getFieldOffset(ordinal), value);
    +  }
    +
    +  @Override
    +  public void setByte(int ordinal, byte value) {
    +    assertIndexIsValid(ordinal);
    +    setNotNullAt(ordinal);
    +    PlatformDependent.UNSAFE.putByte(baseObject, getFieldOffset(ordinal), value);
    +  }
    +
    +  @Override
    +  public void setFloat(int ordinal, float value) {
    +    assertIndexIsValid(ordinal);
    +    setNotNullAt(ordinal);
    +    PlatformDependent.UNSAFE.putFloat(baseObject, getFieldOffset(ordinal), value);
    +  }
    +
    +  @Override
    +  public void setString(int ordinal, String value) {
    +    throw new UnsupportedOperationException();
    +  }
    +
    +  @Override
    +  public int size() {
    +    return numFields;
    +  }
    +
    +  @Override
    +  public int length() {
    +    return size();
    +  }
    +
    +  @Override
    +  public StructType schema() {
    +    return schema;
    +  }
    +
    +  @Override
    +  public Object apply(int i) {
    +    return get(i);
    +  }
    +
    +  @Override
    +  public Object get(int i) {
    +    assertIndexIsValid(i);
    +    assert (schema != null) : "Schema must be defined when calling generic get() method";
    +    final DataType dataType = schema.fields()[i].dataType();
    +    // UnsafeRow is only designed to be invoked by internal code, which only invokes this generic
    +    // get() method when trying to access UTF8String-typed columns. If we refactor the codebase to
    +    // separate the internal and external row interfaces, then internal code can fetch strings via
    +    // a new getUTF8String() method and we'll be able to remove this method.
    +    if (isNullAt(i)) {
    +      return null;
    +    } else if (dataType == StringType) {
    +      return getUTF8String(i);
    +    } else {
    +      throw new UnsupportedOperationException();
    +    }
    +  }
    +
    +  @Override
    +  public boolean isNullAt(int i) {
    +    assertIndexIsValid(i);
    +    return BitSetMethods.isSet(baseObject, baseOffset, i);
    +  }
    +
    +  @Override
    +  public boolean getBoolean(int i) {
    +    assertIndexIsValid(i);
    +    return PlatformDependent.UNSAFE.getBoolean(baseObject, getFieldOffset(i));
    +  }
    +
    +  @Override
    +  public byte getByte(int i) {
    +    assertIndexIsValid(i);
    +    return PlatformDependent.UNSAFE.getByte(baseObject, getFieldOffset(i));
    +  }
    +
    +  @Override
    +  public short getShort(int i) {
    +    assertIndexIsValid(i);
    +    return PlatformDependent.UNSAFE.getShort(baseObject, getFieldOffset(i));
    +  }
    +
    +  @Override
    +  public int getInt(int i) {
    +    assertIndexIsValid(i);
    +    return PlatformDependent.UNSAFE.getInt(baseObject, getFieldOffset(i));
    +  }
    +
    +  @Override
    +  public long getLong(int i) {
    +    assertIndexIsValid(i);
    +    return PlatformDependent.UNSAFE.getLong(baseObject, getFieldOffset(i));
    +  }
    +
    +  @Override
    +  public float getFloat(int i) {
    +    assertIndexIsValid(i);
    +    if (isNullAt(i)) {
    +      return Float.NaN;
    +    } else {
    +      return PlatformDependent.UNSAFE.getFloat(baseObject, getFieldOffset(i));
    +    }
    +  }
    +
    +  @Override
    +  public double getDouble(int i) {
    +    assertIndexIsValid(i);
    +    if (isNullAt(i)) {
    +      return Float.NaN;
    +    } else {
    +      return PlatformDependent.UNSAFE.getDouble(baseObject, getFieldOffset(i));
    +    }
    +  }
    +
    +  public UTF8String getUTF8String(int i) {
    --- End diff --
    
    i created https://issues.apache.org/jira/browse/SPARK-7190 for utf8string backed by memory address


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29284614
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryManager.java ---
    @@ -0,0 +1,176 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import java.util.BitSet;
    +
    +/**
    + * Manages the lifecycle of data pages exchanged between operators.
    + * <p>
    + * Most of the complexity in this class deals with encoding of off-heap addresses into 64-bit longs.
    + * In off-heap mode, memory can be directly addressed with 64-bit longs. In on-heap mode, memory is
    + * addressed by the combination of a base Object reference and a 64-bit offset within that object.
    + * This is a problem when we want to store pointers to data structures inside of other structures,
    + * such as record pointers inside hashmaps or sorting buffers. Even if we decided to use 128 bits
    + * to address memory, we can't just store the address of the base object since it's not guaranteed
    + * to remain stable as the heap gets reorganized due to GC.
    + * <p>
    + * Instead, we use the following approach to encode record pointers in 64-bit longs: for off-heap
    + * mode, just store the raw address, and for on-heap mode use the upper 13 bits of the address to
    + * store a "page number" and the lower 51 bits to store an offset within this page. These page
    + * numbers are used to index into a "page table" array inside of the MemoryManager in order to
    + * retrieve the base object.
    + */
    +public final class MemoryManager {
    +
    +  /**
    +   * The number of entries in the page table.
    +   */
    +  private static final int PAGE_TABLE_SIZE = (int) 1L << 13;
    --- End diff --
    
    Good catch; fixed.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97340664
  
    Test PASSed.
    Refer to this link for build results (access rights to CI server needed): 
    https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31245/
    Test PASSed.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29218869
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeRow.java ---
    @@ -0,0 +1,428 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import scala.collection.Map;
    +import scala.collection.Seq;
    +import scala.collection.mutable.ArraySeq;
    +
    +import javax.annotation.Nullable;
    +import java.math.BigDecimal;
    +import java.sql.Date;
    +import java.util.*;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.DataType;
    +import static org.apache.spark.sql.types.DataTypes.*;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.sql.types.UTF8String;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.bitset.BitSetMethods;
    +
    +/**
    + * An Unsafe implementation of Row which is backed by raw memory instead of Java objects.
    + *
    + * Each tuple has three parts: [null bit set] [values] [variable length portion]
    + *
    + * The bit set is used for null tracking and is aligned to 8-byte word boundaries.  It stores
    + * one bit per field.
    + *
    + * In the `values` region, we store one 8-byte word per field. For fields that hold fixed-length
    + * primitive types, such as long, double, or int, we store the value directly in the word. For
    + * fields with non-primitive or variable-length values, we store a relative offset (w.r.t. the
    + * base address of the row) that points to the beginning of the variable-length field.
    + *
    + * Instances of `UnsafeRow` act as pointers to row data stored in this format, similar to how
    + * `Writable` objects work in Hadoop.
    + */
    +public final class UnsafeRow implements MutableRow {
    +
    +  private Object baseObject;
    +  private long baseOffset;
    +  /** The number of fields in this row, used for calculating the bitset width (and in assertions) */
    --- End diff --
    
    nitpick: if we have comments, let's add a blank line


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29267684
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -265,7 +284,49 @@ case class GeneratedAggregate(
     
             val resultProjection = resultProjectionBuilder()
             Iterator(resultProjection(buffer))
    +      } else if (unsafeEnabled && schemaSupportsUnsafe) {
    +        log.info("Using Unsafe-based aggregator")
    +        val aggregationMap = new UnsafeFixedWidthAggregationMap(
    +          newAggregationBuffer(EmptyRow),
    +          aggregationBufferSchema,
    +          groupKeySchema,
    +          SparkEnv.get.unsafeMemoryManager,
    +          1024 * 16,
    --- End diff --
    
    AFAIK we can't use the Scala named argument syntax because `UnsafeFixedWidthAggregationMap` is implemented in Java, but I can add a line comment explaining this.  Also, I wonder if there's a better choice of default map size here.  If we had statistics / estimates from the optimizer, we could make a better choice here.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97246262
  
    Merged build started.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29215841
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java ---
    @@ -0,0 +1,552 @@
    +/*
    + * 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.spark.unsafe.map;
    +
    +import java.lang.Override;
    +import java.lang.UnsupportedOperationException;
    +import java.util.Iterator;
    +import java.util.LinkedList;
    +import java.util.List;
    +
    +import org.apache.spark.unsafe.*;
    +import org.apache.spark.unsafe.array.ByteArrayMethods;
    +import org.apache.spark.unsafe.array.LongArray;
    +import org.apache.spark.unsafe.bitset.BitSet;
    +import org.apache.spark.unsafe.hash.Murmur3_x86_32;
    +import org.apache.spark.unsafe.memory.*;
    +
    +/**
    + * An append-only hash map where keys and values are contiguous regions of bytes.
    + * <p>
    + * This is backed by a power-of-2-sized hash table, using quadratic probing with triangular numbers,
    + * which is guaranteed to exhaust the space.
    + * <p>
    + * Note that even though we use long for indexing, the map can support up to 2^31 keys because
    + * we use 32 bit MurmurHash. In either case, if the key cardinality is so high, you should probably
    + * be using sorting instead of hashing for better cache locality.
    + * <p>
    + * This class is not thread safe.
    + */
    +public final class BytesToBytesMap {
    +
    +  private static final Murmur3_x86_32 HASHER = new Murmur3_x86_32(0);
    +
    +  private static final HashMapGrowthStrategy growthStrategy = HashMapGrowthStrategy.DOUBLING;
    +
    +  private final MemoryManager memoryManager;
    +
    +  /**
    +   * A linked list for tracking all allocated data pages so that we can free all of our memory.
    +   */
    +  private final List<MemoryBlock> dataPages = new LinkedList<MemoryBlock>();
    +
    +  /**
    +   * The data page that will be used to store keys and values for new hashtable entries. When this
    +   * page becomes full, a new page will be allocated and this pointer will change to point to that
    +   * new page.
    +   */
    +  private MemoryBlock currentDataPage = null;
    +
    +  /**
    +   * Offset into `currentDataPage` that points to the location where new data can be inserted into
    +   * the page.
    +   */
    +  private long pageCursor = 0;
    +
    +  /**
    +   * The size of the data pages that hold key and value data. Map entries cannot span multiple
    +   * pages, so this limits the maximum entry size.
    +   */
    +  private static final long PAGE_SIZE_BYTES = 1L << 26; // 64 megabytes
    +
    +  // This choice of page table size and page size means that we can address up to 500 gigabytes
    +  // of memory.
    +
    +  /**
    +   * A single array to store the key and value.
    +   *
    +   * Position {@code 2 * i} in the array is used to track a pointer to the key at index {@code i},
    +   * while position {@code 2 * i + 1} in the array holds key's full 32-bit hashcode.
    +   */
    +  private LongArray longArray;
    +  // TODO: we're wasting 32 bits of space here; we can probably store fewer bits of the hashcode
    +  // and exploit word-alignment to use fewer bits to hold the address.  This might let us store
    +  // only one long per map entry, increasing the chance that this array will fit in cache at the
    +  // expense of maybe performing more lookups if we have hash collisions.  Say that we stored only
    +  // 27 bits of the hashcode and 37 bits of the address.  37 bits is enough to address 1 terabyte
    +  // of RAM given word-alignment.  If we use 13 bits of this for our page table, that gives us a
    +  // maximum page size of 2^24 * 8 = ~134 megabytes per page. This change will require us to store
    +  // full base addresses in the page table for off-heap mode so that we can reconstruct the full
    +  // absolute memory addresses.
    +
    +  /**
    +   * A {@link BitSet} used to track location of the map where the key is set.
    +   * Size of the bitset should be half of the size of the long array.
    +   */
    +  private BitSet bitset;
    +
    +  private final double loadFactor;
    +
    +  /**
    +   * Number of keys defined in the map.
    +   */
    +  private int size;
    +
    +  /**
    +   * The map will be expanded once the number of keys exceeds this threshold.
    +   */
    +  private int growthThreshold;
    +
    +  /**
    +   * Mask for truncating hashcodes so that they do not exceed the long array's size.
    +   */
    +  private int mask;
    +
    +  /**
    +   * Return value of {@link BytesToBytesMap#lookup(Object, long, int)}.
    +   */
    +  private final Location loc;
    +
    +  private final boolean enablePerfMetrics;
    +
    +  private long timeSpentResizingMs = 0;
    --- End diff --
    
    should be nano sec


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29221410
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/memory/MemoryBlock.java ---
    @@ -0,0 +1,74 @@
    +/*
    + * 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.spark.unsafe.memory;
    +
    +import javax.annotation.Nullable;
    +
    +import org.apache.spark.unsafe.PlatformDependent;
    +
    +/**
    + * A consecutive block of memory, starting at a {@link MemoryLocation} with a fixed size.
    + */
    +public class MemoryBlock extends MemoryLocation {
    +
    +  private final long length;
    +
    +  /**
    +   * Optional page number; used when this MemoryBlock represents a page allocated by a
    +   * MemoryManager. This is package-private and is modified by MemoryManager.
    +   */
    +  int pageNumber = -1;
    --- End diff --
    
    would this be slightly faster if it is a long? since we do quite a bit of shifting and casting from int to long for this field


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29269390
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -265,7 +284,49 @@ case class GeneratedAggregate(
     
             val resultProjection = resultProjectionBuilder()
             Iterator(resultProjection(buffer))
    +      } else if (unsafeEnabled && schemaSupportsUnsafe) {
    +        log.info("Using Unsafe-based aggregator")
    +        val aggregationMap = new UnsafeFixedWidthAggregationMap(
    +          newAggregationBuffer(EmptyRow),
    +          aggregationBufferSchema,
    +          groupKeySchema,
    +          SparkEnv.get.unsafeMemoryManager,
    +          1024 * 16,
    --- End diff --
    
    ah ok nvm. then let's add a comment like
    
    ```java
    1024 * 16,  // page size
    ...
    ```


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29269216
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeFixedWidthAggregationMap.java ---
    @@ -0,0 +1,251 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import java.util.Arrays;
    +import java.util.Iterator;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.StructField;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.map.BytesToBytesMap;
    +import org.apache.spark.unsafe.memory.MemoryLocation;
    +import org.apache.spark.unsafe.memory.MemoryManager;
    +
    +/**
    + * Unsafe-based HashMap for performing aggregations where the aggregated values are fixed-width.
    + *
    + * This map supports a maximum of 2 billion keys.
    + */
    +public final class UnsafeFixedWidthAggregationMap {
    +
    +  /**
    +   * An empty aggregation buffer, encoded in UnsafeRow format. When inserting a new key into the
    +   * map, we copy this buffer and use it as the value.
    +   */
    +  private final long[] emptyAggregationBuffer;
    +
    +  private final StructType aggregationBufferSchema;
    +
    +  private final StructType groupingKeySchema;
    +
    +  /**
    +   * Encodes grouping keys as UnsafeRows.
    +   */
    +  private final UnsafeRowConverter groupingKeyToUnsafeRowConverter;
    +
    +  /**
    +   * A hashmap which maps from opaque bytearray keys to bytearray values.
    +   */
    +  private final BytesToBytesMap map;
    +
    +  /**
    +   * Re-used pointer to the current aggregation buffer
    +   */
    +  private final UnsafeRow currentAggregationBuffer = new UnsafeRow();
    +
    +  /**
    +   * Scratch space that is used when encoding grouping keys into UnsafeRow format.
    +   *
    +   * By default, this is a 1MB array, but it will grow as necessary in case larger keys are
    +   * encountered.
    +   */
    +  private long[] groupingKeyConversionScratchSpace = new long[1024 / 8];
    +
    +  private final boolean enablePerfMetrics;
    +
    +  /**
    +   * @return true if UnsafeFixedWidthAggregationMap supports grouping keys with the given schema,
    +   *         false otherwise.
    +   */
    +  public static boolean supportsGroupKeySchema(StructType schema) {
    +    for (StructField field: schema.fields()) {
    +      if (!UnsafeRow.readableFieldTypes.contains(field.dataType())) {
    +        return false;
    +      }
    +    }
    +    return true;
    +  }
    +
    +  /**
    +   * @return true if UnsafeFixedWidthAggregationMap supports aggregation buffers with the given
    +   *         schema, false otherwise.
    +   */
    +  public static boolean supportsAggregationBufferSchema(StructType schema) {
    +    for (StructField field: schema.fields()) {
    +      if (!UnsafeRow.settableFieldTypes.contains(field.dataType())) {
    +        return false;
    +      }
    +    }
    +    return true;
    +  }
    +
    +  /**
    +   * Create a new UnsafeFixedWidthAggregationMap.
    +   *
    +   * @param emptyAggregationBuffer the default value for new keys (a "zero" of the agg. function)
    +   * @param aggregationBufferSchema the schema of the aggregation buffer, used for row conversion.
    +   * @param groupingKeySchema the schema of the grouping key, used for row conversion.
    +   * @param groupingKeySchema the memory manager used to allocate our Unsafe memory structures.
    +   * @param initialCapacity the initial capacity of the map (a sizing hint to avoid re-hashing).
    +   * @param enablePerfMetrics if true, performance metrics will be recorded (has minor perf impact)
    +   */
    +  public UnsafeFixedWidthAggregationMap(
    +      Row emptyAggregationBuffer,
    +      StructType aggregationBufferSchema,
    +      StructType groupingKeySchema,
    +      MemoryManager memoryManager,
    +      int initialCapacity,
    +      boolean enablePerfMetrics) {
    +    this.emptyAggregationBuffer =
    +      convertToUnsafeRow(emptyAggregationBuffer, aggregationBufferSchema);
    +    this.aggregationBufferSchema = aggregationBufferSchema;
    +    this.groupingKeyToUnsafeRowConverter = new UnsafeRowConverter(groupingKeySchema);
    +    this.groupingKeySchema = groupingKeySchema;
    +    this.map = new BytesToBytesMap(memoryManager, initialCapacity, enablePerfMetrics);
    +    this.enablePerfMetrics = enablePerfMetrics;
    +  }
    +
    +  /**
    +   * Convert a Java object row into an UnsafeRow, allocating it into a new long array.
    +   */
    +  private static long[] convertToUnsafeRow(Row javaRow, StructType schema) {
    +    final UnsafeRowConverter converter = new UnsafeRowConverter(schema);
    +    final long[] unsafeRow = new long[converter.getSizeRequirement(javaRow)];
    +    final long writtenLength =
    +      converter.writeRow(javaRow, unsafeRow, PlatformDependent.LONG_ARRAY_OFFSET);
    +    assert (writtenLength == unsafeRow.length): "Size requirement calculation was wrong!";
    +    return unsafeRow;
    +  }
    +
    +  /**
    +   * Return the aggregation buffer for the current group. For efficiency, all calls to this method
    +   * return the same object.
    +   */
    +  public UnsafeRow getAggregationBuffer(Row groupingKey) {
    +    // Zero out the buffer that's used to hold the current row. This is necessary in order
    +    // to ensure that rows hash properly, since garbage data from the previous row could
    +    // otherwise end up as padding in this row.
    +    Arrays.fill(groupingKeyConversionScratchSpace, 0);
    --- End diff --
    
    Yes.  I think that `Array.fill` is reasonably fast because it can be translated into SIMD operations, but it still doesn't hurt to zero fewer bytes.  This could actually matter in cases where we grow the size of `groupingKeyConversionScratchSpace` in responses to a single large key, since the current code could wind up zeroing much more space than is actually needed.  I'll update this.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97274034
  
    The most recent test failure looks like a possible double-free somewhere.  Here's what I saw when I ran that test locally:
    
    ```
    [info] Test org.apache.spark.unsafe.map.BytesToBytesMapOffHeapSuite.randomizedStressTest started
    java(7099,0x111e21000) malloc: *** error for object 0x7fafec90e800: pointer being freed was not allocated
    *** set a breakpoint in malloc_error_break to debug
    ```
    
    This error is non-deterministic.  Based on some local debugging with `Thread.dumpStack()`, I think that this was due to a race between BytesToBytesMap's finalizer and the tearDown() method in AbstractBytesToBytesMapSuite.  I think that we should remove the finalizers, since they add complexity and are no longer necessary since we have leak detection / cleanup at higher levels.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97280950
  
     Merged build triggered.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97315253
  
      [Test build #732 has started](https://amplab.cs.berkeley.edu/jenkins/job/NewSparkPullRequestBuilder/732/consoleFull) for   PR 5725 at commit [`eeee512`](https://github.com/apache/spark/commit/eeee512bd94d463f741170e904ae186e238f997c).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by AmplabJenkins <gi...@git.apache.org>.
Github user AmplabJenkins commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97272176
  
    Test FAILed.
    Refer to this link for build results (access rights to CI server needed): 
    https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31185/
    Test FAILed.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29218666
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeFixedWidthAggregationMap.java ---
    @@ -0,0 +1,251 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import java.util.Arrays;
    +import java.util.Iterator;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.StructField;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.map.BytesToBytesMap;
    +import org.apache.spark.unsafe.memory.MemoryLocation;
    +import org.apache.spark.unsafe.memory.MemoryManager;
    +
    +/**
    + * Unsafe-based HashMap for performing aggregations where the aggregated values are fixed-width.
    + *
    + * This map supports a maximum of 2 billion keys.
    + */
    +public final class UnsafeFixedWidthAggregationMap {
    +
    +  /**
    +   * An empty aggregation buffer, encoded in UnsafeRow format. When inserting a new key into the
    +   * map, we copy this buffer and use it as the value.
    +   */
    +  private final long[] emptyAggregationBuffer;
    +
    +  private final StructType aggregationBufferSchema;
    +
    +  private final StructType groupingKeySchema;
    +
    +  /**
    +   * Encodes grouping keys as UnsafeRows.
    +   */
    +  private final UnsafeRowConverter groupingKeyToUnsafeRowConverter;
    +
    +  /**
    +   * A hashmap which maps from opaque bytearray keys to bytearray values.
    +   */
    +  private final BytesToBytesMap map;
    +
    +  /**
    +   * Re-used pointer to the current aggregation buffer
    +   */
    +  private final UnsafeRow currentAggregationBuffer = new UnsafeRow();
    +
    +  /**
    +   * Scratch space that is used when encoding grouping keys into UnsafeRow format.
    +   *
    +   * By default, this is a 1MB array, but it will grow as necessary in case larger keys are
    +   * encountered.
    +   */
    +  private long[] groupingKeyConversionScratchSpace = new long[1024 / 8];
    +
    +  private final boolean enablePerfMetrics;
    +
    +  /**
    +   * @return true if UnsafeFixedWidthAggregationMap supports grouping keys with the given schema,
    +   *         false otherwise.
    +   */
    +  public static boolean supportsGroupKeySchema(StructType schema) {
    +    for (StructField field: schema.fields()) {
    +      if (!UnsafeRow.readableFieldTypes.contains(field.dataType())) {
    +        return false;
    +      }
    +    }
    +    return true;
    +  }
    +
    +  /**
    +   * @return true if UnsafeFixedWidthAggregationMap supports aggregation buffers with the given
    +   *         schema, false otherwise.
    +   */
    +  public static boolean supportsAggregationBufferSchema(StructType schema) {
    +    for (StructField field: schema.fields()) {
    +      if (!UnsafeRow.settableFieldTypes.contains(field.dataType())) {
    +        return false;
    +      }
    +    }
    +    return true;
    +  }
    +
    +  /**
    +   * Create a new UnsafeFixedWidthAggregationMap.
    +   *
    +   * @param emptyAggregationBuffer the default value for new keys (a "zero" of the agg. function)
    +   * @param aggregationBufferSchema the schema of the aggregation buffer, used for row conversion.
    +   * @param groupingKeySchema the schema of the grouping key, used for row conversion.
    +   * @param groupingKeySchema the memory manager used to allocate our Unsafe memory structures.
    +   * @param initialCapacity the initial capacity of the map (a sizing hint to avoid re-hashing).
    +   * @param enablePerfMetrics if true, performance metrics will be recorded (has minor perf impact)
    +   */
    +  public UnsafeFixedWidthAggregationMap(
    +      Row emptyAggregationBuffer,
    +      StructType aggregationBufferSchema,
    +      StructType groupingKeySchema,
    +      MemoryManager memoryManager,
    +      int initialCapacity,
    +      boolean enablePerfMetrics) {
    +    this.emptyAggregationBuffer =
    +      convertToUnsafeRow(emptyAggregationBuffer, aggregationBufferSchema);
    +    this.aggregationBufferSchema = aggregationBufferSchema;
    +    this.groupingKeyToUnsafeRowConverter = new UnsafeRowConverter(groupingKeySchema);
    +    this.groupingKeySchema = groupingKeySchema;
    +    this.map = new BytesToBytesMap(memoryManager, initialCapacity, enablePerfMetrics);
    +    this.enablePerfMetrics = enablePerfMetrics;
    +  }
    +
    +  /**
    +   * Convert a Java object row into an UnsafeRow, allocating it into a new long array.
    +   */
    +  private static long[] convertToUnsafeRow(Row javaRow, StructType schema) {
    +    final UnsafeRowConverter converter = new UnsafeRowConverter(schema);
    +    final long[] unsafeRow = new long[converter.getSizeRequirement(javaRow)];
    +    final long writtenLength =
    +      converter.writeRow(javaRow, unsafeRow, PlatformDependent.LONG_ARRAY_OFFSET);
    +    assert (writtenLength == unsafeRow.length): "Size requirement calculation was wrong!";
    +    return unsafeRow;
    +  }
    +
    +  /**
    +   * Return the aggregation buffer for the current group. For efficiency, all calls to this method
    +   * return the same object.
    +   */
    +  public UnsafeRow getAggregationBuffer(Row groupingKey) {
    +    // Zero out the buffer that's used to hold the current row. This is necessary in order
    +    // to ensure that rows hash properly, since garbage data from the previous row could
    +    // otherwise end up as padding in this row.
    +    Arrays.fill(groupingKeyConversionScratchSpace, 0);
    +    final int groupingKeySize = groupingKeyToUnsafeRowConverter.getSizeRequirement(groupingKey);
    +    if (groupingKeySize > groupingKeyConversionScratchSpace.length) {
    +      groupingKeyConversionScratchSpace = new long[groupingKeySize];
    +    }
    +    final long actualGroupingKeySize = groupingKeyToUnsafeRowConverter.writeRow(
    +      groupingKey,
    +      groupingKeyConversionScratchSpace,
    +      PlatformDependent.LONG_ARRAY_OFFSET);
    +    assert (groupingKeySize == actualGroupingKeySize) : "Size requirement calculation was wrong!";
    +
    +    // Probe our map using the serialized key
    +    final BytesToBytesMap.Location loc = map.lookup(
    +      groupingKeyConversionScratchSpace,
    +      PlatformDependent.LONG_ARRAY_OFFSET,
    +      groupingKeySize);
    +    if (!loc.isDefined()) {
    +      // This is the first time that we've seen this grouping key, so we'll insert a copy of the
    +      // empty aggregation buffer into the map:
    +      loc.putNewKey(
    +        groupingKeyConversionScratchSpace,
    +        PlatformDependent.LONG_ARRAY_OFFSET,
    +        groupingKeySize,
    +        emptyAggregationBuffer,
    +        PlatformDependent.LONG_ARRAY_OFFSET,
    +        emptyAggregationBuffer.length
    +      );
    +    }
    +
    +    // Reset the pointer to point to the value that we just stored or looked up:
    +    final MemoryLocation address = loc.getValueAddress();
    +    currentAggregationBuffer.pointTo(
    +      address.getBaseObject(),
    +      address.getBaseOffset(),
    +      aggregationBufferSchema.length(),
    +      aggregationBufferSchema
    +    );
    +    return currentAggregationBuffer;
    +  }
    +
    +  public static class MapEntry {
    --- End diff --
    
    maybe add comment saying this is only used for iterator.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97156621
  
    update: thought about it more. I don't think we need to worry about contention at the moment, since our allocation unit is pretty large.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96910423
  
      [Test build #31113 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31113/consoleFull) for   PR 5725 at commit [`162caf7`](https://github.com/apache/spark/commit/162caf74c15952f6ae0482c1fa74529a0289b039).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97898375
  
    I'm looking into this issue now; these warnings can't be suppressed via the usual annotations mechanism; it requires a special compiler flag.  Planning to submit a patch soon; would be great to get your help in testing it.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97341692
  
    Ok merging in master. Let's make sure we address @marmbrus 's comments in followup prs.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29303752
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -265,7 +283,49 @@ case class GeneratedAggregate(
     
             val resultProjection = resultProjectionBuilder()
             Iterator(resultProjection(buffer))
    +      } else if (unsafeEnabled && schemaSupportsUnsafe) {
    +        log.info("Using Unsafe-based aggregator")
    +        val aggregationMap = new UnsafeFixedWidthAggregationMap(
    +          newAggregationBuffer(EmptyRow),
    +          aggregationBufferSchema,
    +          groupKeySchema,
    +          TaskContext.get.taskMemoryManager(),
    +          1024 * 16, // initial capacity
    +          false // disable tracking of performance metrics
    +        )
    +
    +        while (iter.hasNext) {
    +          val currentRow: Row = iter.next()
    +          val groupKey: Row = groupProjection(currentRow)
    +          val aggregationBuffer = aggregationMap.getAggregationBuffer(groupKey)
    +          updateProjection.target(aggregationBuffer)(joinedRow(aggregationBuffer, currentRow))
    +        }
    +
    +        new Iterator[Row] {
    +          private[this] val mapIterator = aggregationMap.iterator()
    +          private[this] val resultProjection = resultProjectionBuilder()
    +
    +          def hasNext: Boolean = mapIterator.hasNext
    +
    +          def next(): Row = {
    +            val entry = mapIterator.next()
    +            val result = resultProjection(joinedRow(entry.key, entry.value))
    +            if (hasNext) {
    +              result
    +            } else {
    +              // This is the last element in the iterator, so let's free the buffer. Before we do,
    +              // though, we need to make a defensive copy of the result so that we don't return an
    +              // object that might contain dangling pointers to the freed memory
    +              val resultCopy = result.copy()
    +              aggregationMap.free()
    --- End diff --
    
    We're safe in the sense that the memory will eventually get cleaned up, but I think that we would get memory leak exceptions if those warnings / checks have been enabled (the cleanup is always performed but whether we fail tasks is controlled by a flag).  To avoid this issue, I think we need to return a closable iterator interface which lets downstream consumers signal that they will read no more output.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96877807
  
      [Test build #31101 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31101/consoleFull) for   PR 5725 at commit [`b45f070`](https://github.com/apache/spark/commit/b45f0708733e5777fff01c69206d0f1b8efcb7e9).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29301471
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -265,7 +283,49 @@ case class GeneratedAggregate(
     
             val resultProjection = resultProjectionBuilder()
             Iterator(resultProjection(buffer))
    +      } else if (unsafeEnabled && schemaSupportsUnsafe) {
    +        log.info("Using Unsafe-based aggregator")
    +        val aggregationMap = new UnsafeFixedWidthAggregationMap(
    +          newAggregationBuffer(EmptyRow),
    +          aggregationBufferSchema,
    +          groupKeySchema,
    +          TaskContext.get.taskMemoryManager(),
    +          1024 * 16, // initial capacity
    +          false // disable tracking of performance metrics
    --- End diff --
    
    Reynold made the same comment upthread; we can't use Scala-style named arguments here because `UnsafFixedWidthAggregationMap` is a Java class.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by marmbrus <gi...@git.apache.org>.
Github user marmbrus commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29300995
  
    --- Diff: sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/UnsafeRowConverter.scala ---
    @@ -0,0 +1,226 @@
    +/*
    + * 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.spark.sql.catalyst.expressions
    +
    +import org.apache.spark.sql.types._
    +import org.apache.spark.unsafe.PlatformDependent
    +import org.apache.spark.unsafe.array.ByteArrayMethods
    +
    +/**
    + * Converts Rows into UnsafeRow format. This class is NOT thread-safe.
    + *
    + * @param fieldTypes the data types of the row's columns.
    + */
    +class UnsafeRowConverter(fieldTypes: Array[DataType]) {
    +
    +  def this(schema: StructType) {
    +    this(schema.fields.map(_.dataType))
    +  }
    +
    +  /** Re-used pointer to the unsafe row being written */
    +  private[this] val unsafeRow = new UnsafeRow()
    +
    +  /** Functions for encoding each column */
    +  private[this] val writers: Array[UnsafeColumnWriter[Any]] = {
    +    fieldTypes.map(t => UnsafeColumnWriter.forType(t).asInstanceOf[UnsafeColumnWriter[Any]])
    +  }
    +
    +  /** The size, in bytes, of the fixed-length portion of the row, including the null bitmap */
    +  private[this] val fixedLengthSize: Int =
    +    (8 * fieldTypes.length) + UnsafeRow.calculateBitSetWidthInBytes(fieldTypes.length)
    +
    +  /**
    +   * Compute the amount of space, in bytes, required to encode the given row.
    +   */
    +  def getSizeRequirement(row: Row): Int = {
    +    var fieldNumber = 0
    +    var variableLengthFieldSize: Int = 0
    +    while (fieldNumber < writers.length) {
    +      if (!row.isNullAt(fieldNumber)) {
    +        variableLengthFieldSize += writers(fieldNumber).getSize(row(fieldNumber))
    +      }
    +      fieldNumber += 1
    +    }
    +    fixedLengthSize + variableLengthFieldSize
    +  }
    +
    +  /**
    +   * Convert the given row into UnsafeRow format.
    +   *
    +   * @param row the row to convert
    +   * @param baseObject the base object of the destination address
    +   * @param baseOffset the base offset of the destination address
    +   * @return the number of bytes written. This should be equal to `getSizeRequirement(row)`.
    +   */
    +  def writeRow(row: Row, baseObject: Object, baseOffset: Long): Long = {
    +    unsafeRow.pointTo(baseObject, baseOffset, writers.length, null)
    +    var fieldNumber = 0
    +    var appendCursor: Int = fixedLengthSize
    +    while (fieldNumber < writers.length) {
    +      if (row.isNullAt(fieldNumber)) {
    +        unsafeRow.setNullAt(fieldNumber)
    +      } else {
    +        appendCursor += writers(fieldNumber).write(
    +          row(fieldNumber),
    --- End diff --
    
    This is pretty minor, but is there a reason we are boxing here instead of passing the row itself in, allowing a specific accessor to be used for extraction?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29301391
  
    --- Diff: core/src/main/scala/org/apache/spark/executor/Executor.scala ---
    @@ -207,7 +210,23 @@ private[spark] class Executor(
     
             // Run the actual task and measure its runtime.
             taskStart = System.currentTimeMillis()
    -        val value = task.run(taskAttemptId = taskId, attemptNumber = attemptNumber)
    +        var succeeded: Boolean = false
    +        val value = try {
    +          val value = task.run(taskAttemptId = taskId, attemptNumber = attemptNumber)
    +          succeeded = true
    +          value
    +        } finally {
    +          // Release managed memory used by this task
    +          val freedMemory = taskMemoryManager.cleanUpAllAllocatedMemory()
    +          if (succeeded && freedMemory > 0) {
    --- End diff --
    
    I originally considered putting this in Task, but unfortunately `runLocally` doesn't go through `Task`.    We could try to consolidate both of the code paths by using Task in `runLocally`, but I think this will be a larger change (we'd need changes higher up the DAGScheduler call stack to create tasks of the appropriate types, etc., and this might be hard to review).
    
    As a compromise, I'm going to leave the duplicated code in place but add comments so that readers are aware of the duplication and remember to change both copies when making changes.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97274734
  
    As part of UnsafeRowConverter refactoring, I realized that I forgot to add support for a whole bunch of primitives, including booleans.  These are trivial to add, so I'll go ahead and do that now.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97912751
  
    @tgravescs I've opened #5814 to try to fix the compiler warnings (and error due to `Unsafe.setMemory`); it would be great if you could test out that commit and see whether it fixes things in your environment.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97246338
  
      [Test build #31185 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31185/consoleFull) for   PR 5725 at commit [`70a39e4`](https://github.com/apache/spark/commit/70a39e4fe05c31ac73b99614115f1fe9f150e1e6).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by marmbrus <gi...@git.apache.org>.
Github user marmbrus commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29303890
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/SQLConf.scala ---
    @@ -30,6 +30,7 @@ private[spark] object SQLConf {
       val DEFAULT_SIZE_IN_BYTES = "spark.sql.defaultSizeInBytes"
       val SHUFFLE_PARTITIONS = "spark.sql.shuffle.partitions"
       val CODEGEN_ENABLED = "spark.sql.codegen"
    +  val UNSAFE_ENABLED = "spark.sql.unsafe.enabled"
    --- End diff --
    
    unless we think there are going to be other options under unsafe,  we might consider getting rid of `enabled` to match `codegen`


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97145397
  
    When running with off-heap, one concern is proper cleanup of managed memory when tasks fail or are cancelled.  Given that we currently do not share managed memory between tasks running on the same executor, I'm thinking that we should probably move MemoryManager from SparkEnv to TaskContext.  This would let us perform leak-detection when tasks complete; it also simplifies concurrency issues (no contention for the MemoryManager's lock when allocating / freeing blocks, provided that tasks are single-threaded) and reduces the chance that we'll exhaust our page table limit, since each task will have its own independent table.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29202027
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java ---
    @@ -0,0 +1,618 @@
    +/*
    + * 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.spark.unsafe.map;
    +
    +import java.lang.Override;
    +import java.lang.UnsupportedOperationException;
    +import java.util.Iterator;
    +import java.util.LinkedList;
    +import java.util.List;
    +
    +import org.apache.spark.unsafe.*;
    +import org.apache.spark.unsafe.array.ByteArrayMethods;
    +import org.apache.spark.unsafe.array.LongArray;
    +import org.apache.spark.unsafe.bitset.BitSet;
    +import org.apache.spark.unsafe.hash.Murmur3_x86_32;
    +import org.apache.spark.unsafe.memory.*;
    +
    +/**
    + * An append-only hash map where keys and values are contiguous regions of bytes.
    + * <p>
    + * This is backed by a power-of-2-sized hash table, using quadratic probing with triangular numbers,
    + * which is guaranteed to exhaust the space.
    + * <p>
    + * Note that even though we use long for indexing, the map can support up to 2^31 keys because
    + * we use 32 bit MurmurHash. In either case, if the key cardinality is so high, you should probably
    + * be using sorting instead of hashing for better cache locality.
    + * <p>
    + * This class is not thread safe.
    + */
    +public final class BytesToBytesMap {
    +
    +  private static final Murmur3_x86_32 HASHER = new Murmur3_x86_32(0);
    +
    +  private static final HashMapGrowthStrategy growthStrategy = HashMapGrowthStrategy.DOUBLING;
    +
    +  /** Bit mask for the lower 51 bits of a long. */
    +  private static final long MASK_LONG_LOWER_51_BITS = 0x7FFFFFFFFFFFFL;
    +
    +  /** Bit mask for the upper 13 bits of a long */
    +  private static final long MASK_LONG_UPPER_13_BITS = ~MASK_LONG_LOWER_51_BITS;
    +
    +  /** Bit mask for the lower 32 bits of a long */
    +  private static final long MASK_LONG_LOWER_32_BITS = 0xFFFFFFFFL;
    +
    +  private final MemoryAllocator allocator;
    +
    +  /**
    +   * Tracks whether we're using in-heap or off-heap addresses.
    +   */
    +  private final boolean inHeap;
    +
    +  /**
    +   * A linked list for tracking all allocated data pages so that we can free all of our memory.
    +   */
    +  private final List<MemoryBlock> dataPages = new LinkedList<MemoryBlock>();
    +
    +  /**
    +   * The data page that will be used to store keys and values for new hashtable entries. When this
    +   * page becomes full, a new page will be allocated and this pointer will change to point to that
    +   * new page.
    +   */
    +  private MemoryBlock currentDataPage = null;
    +
    +  /**
    +   * Offset into `currentDataPage` that points to the location where new data can be inserted into
    +   * the page.
    +   */
    +  private long pageCursor = 0;
    +
    +  /**
    +   * Similar to an operating system's page table, this array maps page numbers into base object
    +   * pointers, allowing us to translate between the hashtable's internal 64-bit address
    +   * representation and the baseObject+offset representation which we use to support both in- and
    +   * off-heap addresses. When using an off-heap allocator, every entry in this map will be `null`.
    +   * When using an in-heap allocator, the entries in this map will point to pages' base objects.
    +   * Entries are added to this map as new data pages are allocated.
    +   */
    +  private final Object[] pageTable = new Object[PAGE_TABLE_SIZE];
    +
    +  /**
    +   * When using an in-heap allocator, this holds the current page number.
    +   */
    +  private int currentPageNumber = -1;
    +
    +  /**
    +   * The number of entries in the page table.
    +   */
    +  private static final int PAGE_TABLE_SIZE = (int) 1L << 13;
    +
    +  /**
    +   * The size of the data pages that hold key and value data. Map entries cannot span multiple
    +   * pages, so this limits the maximum entry size.
    +   */
    +  private static final long PAGE_SIZE_BYTES = 1L << 26; // 64 megabytes
    +
    +  // This choice of page table size and page size means that we can address up to 500 gigabytes
    +  // of memory.
    +
    +  /**
    +   * A single array to store the key and value.
    +   *
    +   * Position {@code 2 * i} in the array is used to track a pointer to the key at index {@code i},
    +   * while position {@code 2 * i + 1} in the array holds the upper bits of the key's hashcode plus
    +   * the relative offset from the key pointer to the value at index {@code i}.
    +   */
    +  private LongArray longArray;
    +
    +  /**
    +   * A {@link BitSet} used to track location of the map where the key is set.
    +   * Size of the bitset should be half of the size of the long array.
    +   */
    +  private BitSet bitset;
    +
    +  private final double loadFactor;
    +
    +  /**
    +   * Number of keys defined in the map.
    +   */
    +  private int size;
    +
    +  /**
    +   * The map will be expanded once the number of keys exceeds this threshold.
    +   */
    +  private int growthThreshold;
    +
    +  /**
    +   * Mask for truncating hashcodes so that they do not exceed the long array's size.
    +   */
    +  private int mask;
    +
    +  /**
    +   * Return value of {@link BytesToBytesMap#lookup(Object, long, int)}.
    +   */
    +  private final Location loc;
    +
    +  private final boolean enablePerfMetrics;
    +
    +  private long timeSpentResizingMs = 0;
    +
    +  private long numProbes = 0;
    +
    +  private long numKeyLookups = 0;
    +
    +  private long numHashCollisions = 0;
    +
    +  public BytesToBytesMap(
    +      MemoryAllocator allocator,
    +      int initialCapacity,
    +      double loadFactor,
    +      boolean enablePerfMetrics) {
    +    this.inHeap = allocator instanceof HeapMemoryAllocator;
    +    this.allocator = allocator;
    +    this.loadFactor = loadFactor;
    +    this.loc = new Location();
    +    this.enablePerfMetrics = enablePerfMetrics;
    +    allocate(initialCapacity);
    +  }
    +
    +  public BytesToBytesMap(MemoryAllocator allocator, int initialCapacity) {
    +    this(allocator, initialCapacity, 0.70, false);
    +  }
    +
    +  public BytesToBytesMap(
    +      MemoryAllocator allocator,
    +      int initialCapacity,
    +      boolean enablePerfMetrics) {
    +    this(allocator, initialCapacity, 0.70, enablePerfMetrics);
    +  }
    +
    +  @Override
    +  protected void finalize() throws Throwable {
    +    try {
    +      // In case the programmer forgot to call `free()`, try to perform that cleanup now:
    +      free();
    +    } finally {
    +      super.finalize();
    +    }
    +  }
    +
    +  /**
    +   * Returns the number of keys defined in the map.
    +   */
    +  public int size() { return size; }
    +
    +  /**
    +   * Returns an iterator for iterating over the entries of this map.
    +   *
    +   * For efficiency, all calls to `next()` will return the same {@link Location} object.
    +   *
    +   * If any other lookups or operations are performed on this map while iterating over it, including
    +   * `lookup()`, the behavior of the returned iterator is undefined.
    +   */
    +  public Iterator<Location> iterator() {
    +    return new Iterator<Location>() {
    +
    +      private int nextPos = bitset.nextSetBit(0);
    +
    +      @Override
    +      public boolean hasNext() {
    +        return nextPos != -1;
    +      }
    +
    +      @Override
    +      public Location next() {
    +        final int pos = nextPos;
    +        nextPos = bitset.nextSetBit(nextPos + 1);
    +        return loc.with(pos, 0, true);
    +      }
    +
    +      @Override
    +      public void remove() {
    +        throw new UnsupportedOperationException();
    +      }
    +    };
    +  }
    +
    +  /**
    +   * Looks up a key, and return a {@link Location} handle that can be used to test existence
    +   * and read/write values.
    +   *
    +   * This function always return the same {@link Location} instance to avoid object allocation.
    +   */
    +  public Location lookup(
    +      Object keyBaseObject,
    +      long keyBaseOffset,
    +      int keyRowLengthBytes) {
    +    if (enablePerfMetrics) {
    +      numKeyLookups++;
    +    }
    +    final int hashcode = HASHER.hashUnsafeWords(keyBaseObject, keyBaseOffset, keyRowLengthBytes);
    +    int pos = hashcode & mask;
    +    int step = 1;
    +    while (true) {
    +      if (enablePerfMetrics) {
    +        numProbes++;
    +      }
    +      if (!bitset.isSet(pos)) {
    +        // This is a new key.
    +        return loc.with(pos, hashcode, false);
    +      } else {
    +        long stored = longArray.get(pos * 2 + 1);
    +        if (((int) (stored & MASK_LONG_LOWER_32_BITS)) == hashcode) {
    +          // Full hash code matches.  Let's compare the keys for equality.
    +          loc.with(pos, hashcode, true);
    +          if (loc.getKeyLength() == keyRowLengthBytes) {
    +            final MemoryLocation keyAddress = loc.getKeyAddress();
    +            final Object storedKeyBaseObject = keyAddress.getBaseObject();
    +            final long storedKeyBaseOffset = keyAddress.getBaseOffset();
    +            final boolean areEqual = ByteArrayMethods.wordAlignedArrayEquals(
    +              keyBaseObject,
    +              keyBaseOffset,
    +              storedKeyBaseObject,
    +              storedKeyBaseOffset,
    +              keyRowLengthBytes
    +            );
    +            if (areEqual) {
    +              return loc;
    +            } else {
    +              if (enablePerfMetrics) {
    +                numHashCollisions++;
    +              }
    +            }
    +          }
    +        }
    +      }
    +      pos = (pos + step) & mask;
    +      step++;
    +    }
    +  }
    +
    +  /**
    +   * Handle returned by {@link BytesToBytesMap#lookup(Object, long, int)} function.
    +   */
    +  public final class Location {
    +    /** An index into the hash map's Long array */
    +    private int pos;
    +    /** True if this location points to a position where a key is defined, false otherwise */
    +    private boolean isDefined;
    +    /**
    +     * The hashcode of the most recent key passed to
    +     * {@link BytesToBytesMap#lookup(Object, long, int)}. Caching this hashcode here allows us to
    +     * avoid re-hashing the key when storing a value for that key.
    +     */
    +    private int keyHashcode;
    +    private final MemoryLocation keyMemoryLocation = new MemoryLocation();
    +    private final MemoryLocation valueMemoryLocation = new MemoryLocation();
    +    private int keyLength;
    +    private int valueLength;
    +
    +    private void updateAddressesAndSizes(long fullKeyAddress, long offsetFromKeyToValue) {
    +      if (inHeap) {
    +        final Object page = getPage(fullKeyAddress);
    +        final long keyOffsetInPage = getOffsetInPage(fullKeyAddress);
    +        keyMemoryLocation.setObjAndOffset(page, keyOffsetInPage + 8);
    +        valueMemoryLocation.setObjAndOffset(page, keyOffsetInPage + 8 + offsetFromKeyToValue);
    +        keyLength = (int) PlatformDependent.UNSAFE.getLong(page, keyOffsetInPage);
    +        valueLength =
    +          (int) PlatformDependent.UNSAFE.getLong(page, keyOffsetInPage + offsetFromKeyToValue);
    +      } else {
    +        keyMemoryLocation.setObjAndOffset(null, fullKeyAddress + 8);
    +        valueMemoryLocation.setObjAndOffset(null, fullKeyAddress + 8 + offsetFromKeyToValue);
    +        keyLength = (int) PlatformDependent.UNSAFE.getLong(fullKeyAddress);
    +        valueLength = (int) PlatformDependent.UNSAFE.getLong(fullKeyAddress + offsetFromKeyToValue);
    +      }
    +    }
    +
    +    Location with(int pos, int keyHashcode, boolean isDefined) {
    +      this.pos = pos;
    +      this.isDefined = isDefined;
    +      this.keyHashcode = keyHashcode;
    +      if (isDefined) {
    +        final long fullKeyAddress = longArray.get(pos * 2);
    +        final long offsetFromKeyToValue =
    +          (longArray.get(pos * 2 + 1) & ~MASK_LONG_LOWER_32_BITS) >>> 32;
    +        updateAddressesAndSizes(fullKeyAddress, offsetFromKeyToValue);
    +      }
    +      return this;
    +    }
    +
    +    /**
    +     * Returns true if the key is defined at this position, and false otherwise.
    +     */
    +    public boolean isDefined() {
    +      return isDefined;
    +    }
    +
    +    private Object getPage(long fullKeyAddress) {
    +      assert (inHeap);
    +      final int keyPageNumber = (int) ((fullKeyAddress & MASK_LONG_UPPER_13_BITS) >>> 51);
    +      assert (keyPageNumber >= 0 && keyPageNumber < PAGE_TABLE_SIZE);
    +      assert (keyPageNumber <= currentPageNumber);
    +      final Object page = pageTable[keyPageNumber];
    +      assert (page != null);
    +      return page;
    +    }
    +
    +    private long getOffsetInPage(long fullKeyAddress) {
    +      assert (inHeap);
    +      return (fullKeyAddress & MASK_LONG_LOWER_51_BITS);
    +    }
    +
    +    /**
    +     * Returns the address of the key defined at this position.
    +     * This points to the first byte of the key data.
    +     * Unspecified behavior if the key is not defined.
    +     * For efficiency reasons, calls to this method always returns the same MemoryLocation object.
    +     */
    +    public MemoryLocation getKeyAddress() {
    +      assert (isDefined);
    +      return keyMemoryLocation;
    +    }
    +
    +    /**
    +     * Returns the length of the key defined at this position.
    +     * Unspecified behavior if the key is not defined.
    +     */
    +    public int getKeyLength() {
    +      assert (isDefined);
    +      return keyLength;
    +    }
    +
    +    /**
    +     * Returns the address of the value defined at this position.
    +     * This points to the first byte of the value data.
    +     * Unspecified behavior if the key is not defined.
    +     * For efficiency reasons, calls to this method always returns the same MemoryLocation object.
    +     */
    +    public MemoryLocation getValueAddress() {
    +      assert (isDefined);
    +      return valueMemoryLocation;
    +    }
    +
    +    /**
    +     * Returns the length of the value defined at this position.
    +     * Unspecified behavior if the key is not defined.
    +     */
    +    public int getValueLength() {
    +      assert (isDefined);
    +      return valueLength;
    +    }
    +
    +    /**
    +     * Store a new key and value. This method may only be called once for a given key; if you want
    +     * to update the value associated with a key, then you can directly manipulate the bytes stored
    +     * at the value address.
    +     * <p>
    +     * It is only valid to call this method immediately after calling `lookup()` using the same key.
    +     * <p>
    +     * After calling this method, calls to `get[Key|Value]Address()` and `get[Key|Value]Length`
    +     * will return information on the data stored by this `putNewKey` call.
    +     * <p>
    +     * As an example usage, here's the proper way to store a new key:
    +     * <p>
    +     * <pre>
    +     *   Location loc = map.lookup(keyBaseOffset, keyBaseObject, keyLengthInBytes);
    +     *   if (!loc.isDefined()) {
    +     *     loc.putNewKey(keyBaseOffset, keyBaseObject, keyLengthInBytes, ...)
    +     *   }
    +     * </pre>
    +     * <p>
    +     * Unspecified behavior if the key is not defined.
    +     */
    +    public void putNewKey(
    +        Object keyBaseObject,
    +        long keyBaseOffset,
    +        int keyLengthBytes,
    +        Object valueBaseObject,
    +        long valueBaseOffset,
    +        int valueLengthBytes) {
    +      assert (!isDefined) : "Can only set value once for a key";
    +      isDefined = true;
    +      assert (keyLengthBytes % 8 == 0);
    +      assert (valueLengthBytes % 8 == 0);
    +      // Here, we'll copy the data into our data pages. Because we only store a relative offset from
    +      // the key address instead of storing the absolute address of the value, the key and value
    +      // must be stored in the same memory page.
    +      final long requiredSize = 8 + 8 + keyLengthBytes + valueLengthBytes;
    +      assert(requiredSize <= PAGE_SIZE_BYTES);
    +      size++;
    +      bitset.set(pos);
    +
    +      // If there's not enough space in the current page, allocate a new page:
    +      if (currentDataPage == null || PAGE_SIZE_BYTES - pageCursor < requiredSize) {
    +        MemoryBlock newPage = allocator.allocate(PAGE_SIZE_BYTES);
    +        dataPages.add(newPage);
    +        pageCursor = 0;
    +        currentPageNumber++;
    +        pageTable[currentPageNumber] = newPage.getBaseObject();
    +        currentDataPage = newPage;
    +      }
    +
    +      // Compute all of our offsets up-front:
    +      final Object pageBaseObject = currentDataPage.getBaseObject();
    +      final long pageBaseOffset = currentDataPage.getBaseOffset();
    +      final long keySizeOffsetInPage = pageBaseOffset + pageCursor;
    +      pageCursor += 8;
    +      final long keyDataOffsetInPage = pageBaseOffset + pageCursor;
    +      pageCursor += keyLengthBytes;
    +      final long valueSizeOffsetInPage = pageBaseOffset + pageCursor;
    +      pageCursor += 8;
    +      final long valueDataOffsetInPage = pageBaseOffset + pageCursor;
    +      pageCursor += valueLengthBytes;
    +      final long relativeOffsetFromKeyToValue = valueSizeOffsetInPage - keySizeOffsetInPage;
    --- End diff --
    
    I think that this is redundant, actually, since the value always appears after the key, we know the key's length, and we always store the key and value in the same memory block.
    
    If I remove this, we'll have an extra 32 bits of space in the long array that we can use for something else.  Moving to a 64-bit hashcode probably won't make a huge difference.  Is there another good use for this space?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97152921
  
    I think good memory allocator implementations usually have a thread local cache to reduce contention. We can do the same thing too, can't we? The problem with only allocating at the TaskContext level is that you then lack global coordination, and as a result, each task is bounded by total_mem/num_tasks memory, rather than a more dynamic allocation.
    
    Maybe a good way to do this is to have the global memory allocator in SparkEnv, and TaskContext tracks the individual pages used by each task, so it can free it.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29215736
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java ---
    @@ -0,0 +1,552 @@
    +/*
    + * 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.spark.unsafe.map;
    +
    +import java.lang.Override;
    +import java.lang.UnsupportedOperationException;
    +import java.util.Iterator;
    +import java.util.LinkedList;
    +import java.util.List;
    +
    +import org.apache.spark.unsafe.*;
    +import org.apache.spark.unsafe.array.ByteArrayMethods;
    +import org.apache.spark.unsafe.array.LongArray;
    +import org.apache.spark.unsafe.bitset.BitSet;
    +import org.apache.spark.unsafe.hash.Murmur3_x86_32;
    +import org.apache.spark.unsafe.memory.*;
    +
    +/**
    + * An append-only hash map where keys and values are contiguous regions of bytes.
    + * <p>
    + * This is backed by a power-of-2-sized hash table, using quadratic probing with triangular numbers,
    + * which is guaranteed to exhaust the space.
    + * <p>
    + * Note that even though we use long for indexing, the map can support up to 2^31 keys because
    --- End diff --
    
    this is no longer true - we use 32-bit int for index now.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by vanzin <gi...@git.apache.org>.
Github user vanzin commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97902582
  
    Java 6's output:
    
        $ javap sun.misc.Unsafe | grep setMemory
            public native void setMemory(long, long, byte);
    
    So Spark is using an API that doesn't exist there.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by SparkQA <gi...@git.apache.org>.
Github user SparkQA commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-96895948
  
      [Test build #31101 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/31101/consoleFull) for   PR 5725 at commit [`b45f070`](https://github.com/apache/spark/commit/b45f0708733e5777fff01c69206d0f1b8efcb7e9).
     * This patch **fails Spark unit tests**.
     * This patch merges cleanly.
     * This patch adds the following public classes _(experimental)_:
      * `public final class UnsafeFixedWidthAggregationMap `
      * `  public static class MapEntry `
      * `public final class UnsafeRow implements MutableRow `
      * `class UnsafeRowConverter(fieldTypes: Array[DataType]) `
      * `public final class PlatformDependent `
      * `public class ByteArrayMethods `
      * `public final class LongArray `
      * `public final class BitSet `
      * `public final class BitSetMethods `
      * `public final class Murmur3_x86_32 `
      * `public final class BytesToBytesMap `
      * `  public final class Location `
      * `  class Doubling implements HashMapGrowthStrategy `
      * `public class HeapMemoryAllocator implements MemoryAllocator `
      * `public class MemoryBlock extends MemoryLocation `
      * `public class MemoryLocation `
      * `public final class MemoryManager `
      * `public class UnsafeMemoryAllocator implements MemoryAllocator `
    
     * This patch **removes the following dependencies:**
       * `RoaringBitmap-0.4.5.jar`
       * `activation-1.1.jar`
       * `akka-actor_2.10-2.3.4-spark.jar`
       * `akka-remote_2.10-2.3.4-spark.jar`
       * `akka-slf4j_2.10-2.3.4-spark.jar`
       * `aopalliance-1.0.jar`
       * `arpack_combined_all-0.1.jar`
       * `avro-1.7.7.jar`
       * `breeze-macros_2.10-0.11.2.jar`
       * `breeze_2.10-0.11.2.jar`
       * `chill-java-0.5.0.jar`
       * `chill_2.10-0.5.0.jar`
       * `commons-beanutils-1.7.0.jar`
       * `commons-beanutils-core-1.8.0.jar`
       * `commons-cli-1.2.jar`
       * `commons-codec-1.10.jar`
       * `commons-collections-3.2.1.jar`
       * `commons-compress-1.4.1.jar`
       * `commons-configuration-1.6.jar`
       * `commons-digester-1.8.jar`
       * `commons-httpclient-3.1.jar`
       * `commons-io-2.1.jar`
       * `commons-lang-2.5.jar`
       * `commons-lang3-3.3.2.jar`
       * `commons-math-2.1.jar`
       * `commons-math3-3.4.1.jar`
       * `commons-net-2.2.jar`
       * `compress-lzf-1.0.0.jar`
       * `config-1.2.1.jar`
       * `core-1.1.2.jar`
       * `curator-client-2.4.0.jar`
       * `curator-framework-2.4.0.jar`
       * `curator-recipes-2.4.0.jar`
       * `gmbal-api-only-3.0.0-b023.jar`
       * `grizzly-framework-2.1.2.jar`
       * `grizzly-http-2.1.2.jar`
       * `grizzly-http-server-2.1.2.jar`
       * `grizzly-http-servlet-2.1.2.jar`
       * `grizzly-rcm-2.1.2.jar`
       * `groovy-all-2.3.7.jar`
       * `guava-14.0.1.jar`
       * `guice-3.0.jar`
       * `hadoop-annotations-2.2.0.jar`
       * `hadoop-auth-2.2.0.jar`
       * `hadoop-client-2.2.0.jar`
       * `hadoop-common-2.2.0.jar`
       * `hadoop-hdfs-2.2.0.jar`
       * `hadoop-mapreduce-client-app-2.2.0.jar`
       * `hadoop-mapreduce-client-common-2.2.0.jar`
       * `hadoop-mapreduce-client-core-2.2.0.jar`
       * `hadoop-mapreduce-client-jobclient-2.2.0.jar`
       * `hadoop-mapreduce-client-shuffle-2.2.0.jar`
       * `hadoop-yarn-api-2.2.0.jar`
       * `hadoop-yarn-client-2.2.0.jar`
       * `hadoop-yarn-common-2.2.0.jar`
       * `hadoop-yarn-server-common-2.2.0.jar`
       * `ivy-2.4.0.jar`
       * `jackson-annotations-2.4.0.jar`
       * `jackson-core-2.4.4.jar`
       * `jackson-core-asl-1.8.8.jar`
       * `jackson-databind-2.4.4.jar`
       * `jackson-jaxrs-1.8.8.jar`
       * `jackson-mapper-asl-1.8.8.jar`
       * `jackson-module-scala_2.10-2.4.4.jar`
       * `jackson-xc-1.8.8.jar`
       * `jansi-1.4.jar`
       * `javax.inject-1.jar`
       * `javax.servlet-3.0.0.v201112011016.jar`
       * `javax.servlet-3.1.jar`
       * `javax.servlet-api-3.0.1.jar`
       * `jaxb-api-2.2.2.jar`
       * `jaxb-impl-2.2.3-1.jar`
       * `jcl-over-slf4j-1.7.10.jar`
       * `jersey-client-1.9.jar`
       * `jersey-core-1.9.jar`
       * `jersey-grizzly2-1.9.jar`
       * `jersey-guice-1.9.jar`
       * `jersey-json-1.9.jar`
       * `jersey-server-1.9.jar`
       * `jersey-test-framework-core-1.9.jar`
       * `jersey-test-framework-grizzly2-1.9.jar`
       * `jets3t-0.7.1.jar`
       * `jettison-1.1.jar`
       * `jetty-util-6.1.26.jar`
       * `jline-0.9.94.jar`
       * `jline-2.10.4.jar`
       * `jodd-core-3.6.3.jar`
       * `json4s-ast_2.10-3.2.10.jar`
       * `json4s-core_2.10-3.2.10.jar`
       * `json4s-jackson_2.10-3.2.10.jar`
       * `jsr305-1.3.9.jar`
       * `jtransforms-2.4.0.jar`
       * `jul-to-slf4j-1.7.10.jar`
       * `kryo-2.21.jar`
       * `log4j-1.2.17.jar`
       * `lz4-1.2.0.jar`
       * `management-api-3.0.0-b012.jar`
       * `mesos-0.21.0-shaded-protobuf.jar`
       * `metrics-core-3.1.0.jar`
       * `metrics-graphite-3.1.0.jar`
       * `metrics-json-3.1.0.jar`
       * `metrics-jvm-3.1.0.jar`
       * `minlog-1.2.jar`
       * `netty-3.8.0.Final.jar`
       * `netty-all-4.0.23.Final.jar`
       * `objenesis-1.2.jar`
       * `opencsv-2.3.jar`
       * `oro-2.0.8.jar`
       * `paranamer-2.6.jar`
       * `parquet-column-1.6.0rc3.jar`
       * `parquet-common-1.6.0rc3.jar`
       * `parquet-encoding-1.6.0rc3.jar`
       * `parquet-format-2.2.0-rc1.jar`
       * `parquet-generator-1.6.0rc3.jar`
       * `parquet-hadoop-1.6.0rc3.jar`
       * `parquet-jackson-1.6.0rc3.jar`
       * `protobuf-java-2.4.1.jar`
       * `protobuf-java-2.5.0-spark.jar`
       * `py4j-0.8.2.1.jar`
       * `pyrolite-2.0.1.jar`
       * `quasiquotes_2.10-2.0.1.jar`
       * `reflectasm-1.07-shaded.jar`
       * `scala-compiler-2.10.4.jar`
       * `scala-library-2.10.4.jar`
       * `scala-reflect-2.10.4.jar`
       * `scalap-2.10.4.jar`
       * `scalatest_2.10-2.2.1.jar`
       * `slf4j-api-1.7.10.jar`
       * `slf4j-log4j12-1.7.10.jar`
       * `snappy-java-1.1.1.7.jar`
       * `spark-bagel_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-catalyst_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-core_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-graphx_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-launcher_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-mllib_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-network-common_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-network-shuffle_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-repl_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-sql_2.10-1.4.0-SNAPSHOT.jar`
       * `spark-streaming_2.10-1.4.0-SNAPSHOT.jar`
       * `spire-macros_2.10-0.7.4.jar`
       * `spire_2.10-0.7.4.jar`
       * `stax-api-1.0.1.jar`
       * `stream-2.7.0.jar`
       * `tachyon-0.6.4.jar`
       * `tachyon-client-0.6.4.jar`
       * `uncommons-maths-1.2.2a.jar`
       * `unused-1.0.0.jar`
       * `xmlenc-0.52.jar`
       * `xz-1.0.jar`
       * `zookeeper-3.4.5.jar`



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29221663
  
    --- Diff: unsafe/src/main/java/org/apache/spark/unsafe/map/BytesToBytesMap.java ---
    @@ -0,0 +1,552 @@
    +/*
    + * 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.spark.unsafe.map;
    +
    +import java.lang.Override;
    +import java.lang.UnsupportedOperationException;
    +import java.util.Iterator;
    +import java.util.LinkedList;
    +import java.util.List;
    +
    +import org.apache.spark.unsafe.*;
    +import org.apache.spark.unsafe.array.ByteArrayMethods;
    +import org.apache.spark.unsafe.array.LongArray;
    +import org.apache.spark.unsafe.bitset.BitSet;
    +import org.apache.spark.unsafe.hash.Murmur3_x86_32;
    +import org.apache.spark.unsafe.memory.*;
    +
    +/**
    + * An append-only hash map where keys and values are contiguous regions of bytes.
    + * <p>
    + * This is backed by a power-of-2-sized hash table, using quadratic probing with triangular numbers,
    + * which is guaranteed to exhaust the space.
    + * <p>
    + * Note that even though we use long for indexing, the map can support up to 2^31 keys because
    + * we use 32 bit MurmurHash. In either case, if the key cardinality is so high, you should probably
    + * be using sorting instead of hashing for better cache locality.
    + * <p>
    + * This class is not thread safe.
    + */
    +public final class BytesToBytesMap {
    +
    +  private static final Murmur3_x86_32 HASHER = new Murmur3_x86_32(0);
    +
    +  private static final HashMapGrowthStrategy growthStrategy = HashMapGrowthStrategy.DOUBLING;
    +
    +  private final MemoryManager memoryManager;
    +
    +  /**
    +   * A linked list for tracking all allocated data pages so that we can free all of our memory.
    +   */
    +  private final List<MemoryBlock> dataPages = new LinkedList<MemoryBlock>();
    +
    +  /**
    +   * The data page that will be used to store keys and values for new hashtable entries. When this
    +   * page becomes full, a new page will be allocated and this pointer will change to point to that
    +   * new page.
    +   */
    +  private MemoryBlock currentDataPage = null;
    +
    +  /**
    +   * Offset into `currentDataPage` that points to the location where new data can be inserted into
    +   * the page.
    +   */
    +  private long pageCursor = 0;
    +
    +  /**
    +   * The size of the data pages that hold key and value data. Map entries cannot span multiple
    +   * pages, so this limits the maximum entry size.
    +   */
    +  private static final long PAGE_SIZE_BYTES = 1L << 26; // 64 megabytes
    +
    +  // This choice of page table size and page size means that we can address up to 500 gigabytes
    +  // of memory.
    +
    +  /**
    +   * A single array to store the key and value.
    +   *
    +   * Position {@code 2 * i} in the array is used to track a pointer to the key at index {@code i},
    +   * while position {@code 2 * i + 1} in the array holds key's full 32-bit hashcode.
    +   */
    +  private LongArray longArray;
    +  // TODO: we're wasting 32 bits of space here; we can probably store fewer bits of the hashcode
    +  // and exploit word-alignment to use fewer bits to hold the address.  This might let us store
    +  // only one long per map entry, increasing the chance that this array will fit in cache at the
    +  // expense of maybe performing more lookups if we have hash collisions.  Say that we stored only
    +  // 27 bits of the hashcode and 37 bits of the address.  37 bits is enough to address 1 terabyte
    +  // of RAM given word-alignment.  If we use 13 bits of this for our page table, that gives us a
    +  // maximum page size of 2^24 * 8 = ~134 megabytes per page. This change will require us to store
    +  // full base addresses in the page table for off-heap mode so that we can reconstruct the full
    +  // absolute memory addresses.
    +
    +  /**
    +   * A {@link BitSet} used to track location of the map where the key is set.
    +   * Size of the bitset should be half of the size of the long array.
    +   */
    +  private BitSet bitset;
    +
    +  private final double loadFactor;
    +
    +  /**
    +   * Number of keys defined in the map.
    +   */
    +  private int size;
    +
    +  /**
    +   * The map will be expanded once the number of keys exceeds this threshold.
    +   */
    +  private int growthThreshold;
    +
    +  /**
    +   * Mask for truncating hashcodes so that they do not exceed the long array's size.
    +   */
    +  private int mask;
    +
    +  /**
    +   * Return value of {@link BytesToBytesMap#lookup(Object, long, int)}.
    +   */
    +  private final Location loc;
    +
    +  private final boolean enablePerfMetrics;
    +
    +  private long timeSpentResizingMs = 0;
    +
    +  private long numProbes = 0;
    +
    +  private long numKeyLookups = 0;
    +
    +  private long numHashCollisions = 0;
    +
    +  public BytesToBytesMap(
    +      MemoryManager memoryManager,
    +      int initialCapacity,
    +      double loadFactor,
    +      boolean enablePerfMetrics) {
    +    this.memoryManager = memoryManager;
    +    this.loadFactor = loadFactor;
    +    this.loc = new Location();
    +    this.enablePerfMetrics = enablePerfMetrics;
    +    allocate(initialCapacity);
    +  }
    +
    +  public BytesToBytesMap(MemoryManager memoryManager, int initialCapacity) {
    +    this(memoryManager, initialCapacity, 0.70, false);
    +  }
    +
    +  public BytesToBytesMap(
    +      MemoryManager memoryManager,
    +      int initialCapacity,
    +      boolean enablePerfMetrics) {
    +    this(memoryManager, initialCapacity, 0.70, enablePerfMetrics);
    +  }
    +
    +  @Override
    +  protected void finalize() throws Throwable {
    +    try {
    +      // In case the programmer forgot to call `free()`, try to perform that cleanup now:
    +      free();
    +    } finally {
    +      super.finalize();
    +    }
    +  }
    +
    +  /**
    +   * Returns the number of keys defined in the map.
    +   */
    +  public int size() { return size; }
    +
    +  /**
    +   * Returns an iterator for iterating over the entries of this map.
    +   *
    +   * For efficiency, all calls to `next()` will return the same {@link Location} object.
    +   *
    +   * If any other lookups or operations are performed on this map while iterating over it, including
    +   * `lookup()`, the behavior of the returned iterator is undefined.
    +   */
    +  public Iterator<Location> iterator() {
    +    return new Iterator<Location>() {
    +
    +      private int nextPos = bitset.nextSetBit(0);
    +
    +      @Override
    +      public boolean hasNext() {
    +        return nextPos != -1;
    +      }
    +
    +      @Override
    +      public Location next() {
    +        final int pos = nextPos;
    +        nextPos = bitset.nextSetBit(nextPos + 1);
    +        return loc.with(pos, 0, true);
    +      }
    +
    +      @Override
    +      public void remove() {
    +        throw new UnsupportedOperationException();
    +      }
    +    };
    +  }
    +
    +  /**
    +   * Looks up a key, and return a {@link Location} handle that can be used to test existence
    +   * and read/write values.
    +   *
    +   * This function always return the same {@link Location} instance to avoid object allocation.
    +   */
    +  public Location lookup(
    +      Object keyBaseObject,
    +      long keyBaseOffset,
    +      int keyRowLengthBytes) {
    +    if (enablePerfMetrics) {
    +      numKeyLookups++;
    +    }
    +    final int hashcode = HASHER.hashUnsafeWords(keyBaseObject, keyBaseOffset, keyRowLengthBytes);
    +    int pos = hashcode & mask;
    +    int step = 1;
    +    while (true) {
    +      if (enablePerfMetrics) {
    +        numProbes++;
    +      }
    +      if (!bitset.isSet(pos)) {
    +        // This is a new key.
    +        return loc.with(pos, hashcode, false);
    +      } else {
    +        long stored = longArray.get(pos * 2 + 1);
    +        if ((int) (stored) == hashcode) {
    +          // Full hash code matches.  Let's compare the keys for equality.
    +          loc.with(pos, hashcode, true);
    +          if (loc.getKeyLength() == keyRowLengthBytes) {
    +            final MemoryLocation keyAddress = loc.getKeyAddress();
    +            final Object storedKeyBaseObject = keyAddress.getBaseObject();
    +            final long storedKeyBaseOffset = keyAddress.getBaseOffset();
    +            final boolean areEqual = ByteArrayMethods.wordAlignedArrayEquals(
    +              keyBaseObject,
    +              keyBaseOffset,
    +              storedKeyBaseObject,
    +              storedKeyBaseOffset,
    +              keyRowLengthBytes
    +            );
    +            if (areEqual) {
    +              return loc;
    +            } else {
    +              if (enablePerfMetrics) {
    +                numHashCollisions++;
    +              }
    +            }
    +          }
    +        }
    +      }
    +      pos = (pos + step) & mask;
    +      step++;
    +    }
    +  }
    +
    +  /**
    +   * Handle returned by {@link BytesToBytesMap#lookup(Object, long, int)} function.
    +   */
    +  public final class Location {
    +    /** An index into the hash map's Long array */
    +    private int pos;
    +    /** True if this location points to a position where a key is defined, false otherwise */
    +    private boolean isDefined;
    +    /**
    +     * The hashcode of the most recent key passed to
    +     * {@link BytesToBytesMap#lookup(Object, long, int)}. Caching this hashcode here allows us to
    +     * avoid re-hashing the key when storing a value for that key.
    +     */
    +    private int keyHashcode;
    +    private final MemoryLocation keyMemoryLocation = new MemoryLocation();
    +    private final MemoryLocation valueMemoryLocation = new MemoryLocation();
    +    private int keyLength;
    +    private int valueLength;
    +
    +    private void updateAddressesAndSizes(long fullKeyAddress) {
    +        final Object page = memoryManager.getPage(fullKeyAddress);
    +        final long keyOffsetInPage = memoryManager.getOffsetInPage(fullKeyAddress);
    +        keyMemoryLocation.setObjAndOffset(page, keyOffsetInPage + 8);
    +        keyLength = (int) PlatformDependent.UNSAFE.getLong(page, keyOffsetInPage);
    +        valueMemoryLocation.setObjAndOffset(page, keyOffsetInPage + 8 + keyLength + 8);
    +        valueLength = (int) PlatformDependent.UNSAFE.getLong(page, keyOffsetInPage + 8 + keyLength);
    +    }
    +
    +    Location with(int pos, int keyHashcode, boolean isDefined) {
    +      this.pos = pos;
    +      this.isDefined = isDefined;
    +      this.keyHashcode = keyHashcode;
    +      if (isDefined) {
    +        final long fullKeyAddress = longArray.get(pos * 2);
    +        updateAddressesAndSizes(fullKeyAddress);
    +      }
    +      return this;
    +    }
    +
    +    /**
    +     * Returns true if the key is defined at this position, and false otherwise.
    +     */
    +    public boolean isDefined() {
    +      return isDefined;
    +    }
    +
    +    /**
    +     * Returns the address of the key defined at this position.
    +     * This points to the first byte of the key data.
    +     * Unspecified behavior if the key is not defined.
    +     * For efficiency reasons, calls to this method always returns the same MemoryLocation object.
    +     */
    +    public MemoryLocation getKeyAddress() {
    +      assert (isDefined);
    +      return keyMemoryLocation;
    +    }
    +
    +    /**
    +     * Returns the length of the key defined at this position.
    +     * Unspecified behavior if the key is not defined.
    +     */
    +    public int getKeyLength() {
    +      assert (isDefined);
    +      return keyLength;
    +    }
    +
    +    /**
    +     * Returns the address of the value defined at this position.
    +     * This points to the first byte of the value data.
    +     * Unspecified behavior if the key is not defined.
    +     * For efficiency reasons, calls to this method always returns the same MemoryLocation object.
    +     */
    +    public MemoryLocation getValueAddress() {
    +      assert (isDefined);
    +      return valueMemoryLocation;
    +    }
    +
    +    /**
    +     * Returns the length of the value defined at this position.
    +     * Unspecified behavior if the key is not defined.
    +     */
    +    public int getValueLength() {
    +      assert (isDefined);
    +      return valueLength;
    +    }
    +
    +    /**
    +     * Store a new key and value. This method may only be called once for a given key; if you want
    +     * to update the value associated with a key, then you can directly manipulate the bytes stored
    +     * at the value address.
    +     * <p>
    +     * It is only valid to call this method immediately after calling `lookup()` using the same key.
    +     * <p>
    +     * After calling this method, calls to `get[Key|Value]Address()` and `get[Key|Value]Length`
    +     * will return information on the data stored by this `putNewKey` call.
    +     * <p>
    +     * As an example usage, here's the proper way to store a new key:
    +     * <p>
    +     * <pre>
    +     *   Location loc = map.lookup(keyBaseOffset, keyBaseObject, keyLengthInBytes);
    +     *   if (!loc.isDefined()) {
    +     *     loc.putNewKey(keyBaseOffset, keyBaseObject, keyLengthInBytes, ...)
    +     *   }
    +     * </pre>
    +     * <p>
    +     * Unspecified behavior if the key is not defined.
    +     */
    +    public void putNewKey(
    +        Object keyBaseObject,
    +        long keyBaseOffset,
    +        int keyLengthBytes,
    +        Object valueBaseObject,
    +        long valueBaseOffset,
    +        int valueLengthBytes) {
    +      assert (!isDefined) : "Can only set value once for a key";
    +      isDefined = true;
    +      assert (keyLengthBytes % 8 == 0);
    +      assert (valueLengthBytes % 8 == 0);
    +      // Here, we'll copy the data into our data pages. Because we only store a relative offset from
    +      // the key address instead of storing the absolute address of the value, the key and value
    +      // must be stored in the same memory page.
    +      final long requiredSize = 8 + 8 + keyLengthBytes + valueLengthBytes;
    --- End diff --
    
    should say what the 8 + 8 are (key len + value len?)


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97281833
  
    LGTM. There are some issues, but we can easily address them in followup PRs.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by marmbrus <gi...@git.apache.org>.
Github user marmbrus commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29303406
  
    --- Diff: sql/core/src/main/scala/org/apache/spark/sql/execution/GeneratedAggregate.scala ---
    @@ -265,7 +283,49 @@ case class GeneratedAggregate(
     
             val resultProjection = resultProjectionBuilder()
             Iterator(resultProjection(buffer))
    +      } else if (unsafeEnabled && schemaSupportsUnsafe) {
    +        log.info("Using Unsafe-based aggregator")
    +        val aggregationMap = new UnsafeFixedWidthAggregationMap(
    +          newAggregationBuffer(EmptyRow),
    +          aggregationBufferSchema,
    +          groupKeySchema,
    +          TaskContext.get.taskMemoryManager(),
    +          1024 * 16, // initial capacity
    +          false // disable tracking of performance metrics
    +        )
    +
    +        while (iter.hasNext) {
    +          val currentRow: Row = iter.next()
    +          val groupKey: Row = groupProjection(currentRow)
    +          val aggregationBuffer = aggregationMap.getAggregationBuffer(groupKey)
    +          updateProjection.target(aggregationBuffer)(joinedRow(aggregationBuffer, currentRow))
    +        }
    +
    +        new Iterator[Row] {
    +          private[this] val mapIterator = aggregationMap.iterator()
    +          private[this] val resultProjection = resultProjectionBuilder()
    +
    +          def hasNext: Boolean = mapIterator.hasNext
    +
    +          def next(): Row = {
    +            val entry = mapIterator.next()
    +            val result = resultProjection(joinedRow(entry.key, entry.value))
    +            if (hasNext) {
    +              result
    +            } else {
    +              // This is the last element in the iterator, so let's free the buffer. Before we do,
    +              // though, we need to make a defensive copy of the result so that we don't return an
    +              // object that might contain dangling pointers to the freed memory
    +              val resultCopy = result.copy()
    +              aggregationMap.free()
    --- End diff --
    
    Checking my understanding here... We are safe for takes that don't exhaust the iterator because of  some registration that is happening due to `TaskContext.get.taskMemoryManager()` above?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by tgravescs <gi...@git.apache.org>.
Github user tgravescs commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97889088
  
    not sure what your question is exactly, I think the last one is an error instead of warning.  I didn't specifying anything special in build command: mvn -Pyarn -Phadoop-2.4 -DskipTests clean package install



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by rxin <gi...@git.apache.org>.
Github user rxin commented on a diff in the pull request:

    https://github.com/apache/spark/pull/5725#discussion_r29215857
  
    --- Diff: sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/UnsafeFixedWidthAggregationMap.java ---
    @@ -0,0 +1,251 @@
    +/*
    + * 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.spark.sql.catalyst.expressions;
    +
    +import java.util.Arrays;
    +import java.util.Iterator;
    +
    +import org.apache.spark.sql.Row;
    +import org.apache.spark.sql.types.StructField;
    +import org.apache.spark.sql.types.StructType;
    +import org.apache.spark.unsafe.PlatformDependent;
    +import org.apache.spark.unsafe.map.BytesToBytesMap;
    +import org.apache.spark.unsafe.memory.MemoryLocation;
    +import org.apache.spark.unsafe.memory.MemoryManager;
    +
    +/**
    + * Unsafe-based HashMap for performing aggregations where the aggregated values are fixed-width.
    + *
    + * This map supports a maximum of 2 billion keys.
    + */
    +public final class UnsafeFixedWidthAggregationMap {
    +
    +  /**
    +   * An empty aggregation buffer, encoded in UnsafeRow format. When inserting a new key into the
    +   * map, we copy this buffer and use it as the value.
    +   */
    +  private final long[] emptyAggregationBuffer;
    +
    +  private final StructType aggregationBufferSchema;
    +
    +  private final StructType groupingKeySchema;
    +
    +  /**
    +   * Encodes grouping keys as UnsafeRows.
    +   */
    +  private final UnsafeRowConverter groupingKeyToUnsafeRowConverter;
    +
    +  /**
    +   * A hashmap which maps from opaque bytearray keys to bytearray values.
    +   */
    +  private final BytesToBytesMap map;
    +
    +  /**
    +   * Re-used pointer to the current aggregation buffer
    +   */
    +  private final UnsafeRow currentAggregationBuffer = new UnsafeRow();
    +
    +  /**
    +   * Scratch space that is used when encoding grouping keys into UnsafeRow format.
    +   *
    +   * By default, this is a 1MB array, but it will grow as necessary in case larger keys are
    +   * encountered.
    +   */
    +  private long[] groupingKeyConversionScratchSpace = new long[1024 / 8];
    +
    +  private final boolean enablePerfMetrics;
    +
    +  /**
    +   * @return true if UnsafeFixedWidthAggregationMap supports grouping keys with the given schema,
    +   *         false otherwise.
    +   */
    +  public static boolean supportsGroupKeySchema(StructType schema) {
    +    for (StructField field: schema.fields()) {
    +      if (!UnsafeRow.readableFieldTypes.contains(field.dataType())) {
    +        return false;
    +      }
    +    }
    +    return true;
    +  }
    +
    +  /**
    +   * @return true if UnsafeFixedWidthAggregationMap supports aggregation buffers with the given
    +   *         schema, false otherwise.
    +   */
    +  public static boolean supportsAggregationBufferSchema(StructType schema) {
    +    for (StructField field: schema.fields()) {
    +      if (!UnsafeRow.settableFieldTypes.contains(field.dataType())) {
    +        return false;
    +      }
    +    }
    +    return true;
    +  }
    +
    +  /**
    +   * Create a new UnsafeFixedWidthAggregationMap.
    +   *
    +   * @param emptyAggregationBuffer the default value for new keys (a "zero" of the agg. function)
    +   * @param aggregationBufferSchema the schema of the aggregation buffer, used for row conversion.
    +   * @param groupingKeySchema the schema of the grouping key, used for row conversion.
    +   * @param groupingKeySchema the memory manager used to allocate our Unsafe memory structures.
    +   * @param initialCapacity the initial capacity of the map (a sizing hint to avoid re-hashing).
    +   * @param enablePerfMetrics if true, performance metrics will be recorded (has minor perf impact)
    +   */
    +  public UnsafeFixedWidthAggregationMap(
    +      Row emptyAggregationBuffer,
    +      StructType aggregationBufferSchema,
    +      StructType groupingKeySchema,
    +      MemoryManager memoryManager,
    +      int initialCapacity,
    +      boolean enablePerfMetrics) {
    +    this.emptyAggregationBuffer =
    +      convertToUnsafeRow(emptyAggregationBuffer, aggregationBufferSchema);
    +    this.aggregationBufferSchema = aggregationBufferSchema;
    +    this.groupingKeyToUnsafeRowConverter = new UnsafeRowConverter(groupingKeySchema);
    +    this.groupingKeySchema = groupingKeySchema;
    +    this.map = new BytesToBytesMap(memoryManager, initialCapacity, enablePerfMetrics);
    +    this.enablePerfMetrics = enablePerfMetrics;
    +  }
    +
    +  /**
    +   * Convert a Java object row into an UnsafeRow, allocating it into a new long array.
    +   */
    +  private static long[] convertToUnsafeRow(Row javaRow, StructType schema) {
    +    final UnsafeRowConverter converter = new UnsafeRowConverter(schema);
    +    final long[] unsafeRow = new long[converter.getSizeRequirement(javaRow)];
    +    final long writtenLength =
    +      converter.writeRow(javaRow, unsafeRow, PlatformDependent.LONG_ARRAY_OFFSET);
    +    assert (writtenLength == unsafeRow.length): "Size requirement calculation was wrong!";
    +    return unsafeRow;
    +  }
    +
    +  /**
    +   * Return the aggregation buffer for the current group. For efficiency, all calls to this method
    +   * return the same object.
    +   */
    +  public UnsafeRow getAggregationBuffer(Row groupingKey) {
    +    // Zero out the buffer that's used to hold the current row. This is necessary in order
    +    // to ensure that rows hash properly, since garbage data from the previous row could
    +    // otherwise end up as padding in this row.
    +    Arrays.fill(groupingKeyConversionScratchSpace, 0);
    +    final int groupingKeySize = groupingKeyToUnsafeRowConverter.getSizeRequirement(groupingKey);
    +    if (groupingKeySize > groupingKeyConversionScratchSpace.length) {
    +      groupingKeyConversionScratchSpace = new long[groupingKeySize];
    +    }
    +    final long actualGroupingKeySize = groupingKeyToUnsafeRowConverter.writeRow(
    +      groupingKey,
    +      groupingKeyConversionScratchSpace,
    +      PlatformDependent.LONG_ARRAY_OFFSET);
    +    assert (groupingKeySize == actualGroupingKeySize) : "Size requirement calculation was wrong!";
    +
    +    // Probe our map using the serialized key
    +    final BytesToBytesMap.Location loc = map.lookup(
    +      groupingKeyConversionScratchSpace,
    +      PlatformDependent.LONG_ARRAY_OFFSET,
    +      groupingKeySize);
    +    if (!loc.isDefined()) {
    +      // This is the first time that we've seen this grouping key, so we'll insert a copy of the
    +      // empty aggregation buffer into the map:
    +      loc.putNewKey(
    +        groupingKeyConversionScratchSpace,
    +        PlatformDependent.LONG_ARRAY_OFFSET,
    +        groupingKeySize,
    +        emptyAggregationBuffer,
    +        PlatformDependent.LONG_ARRAY_OFFSET,
    +        emptyAggregationBuffer.length
    +      );
    +    }
    +
    +    // Reset the pointer to point to the value that we just stored or looked up:
    +    final MemoryLocation address = loc.getValueAddress();
    +    currentAggregationBuffer.pointTo(
    +      address.getBaseObject(),
    +      address.getBaseOffset(),
    +      aggregationBufferSchema.length(),
    +      aggregationBufferSchema
    +    );
    +    return currentAggregationBuffer;
    +  }
    +
    +  public static class MapEntry {
    +    public final UnsafeRow key = new UnsafeRow();
    +    public final UnsafeRow value = new UnsafeRow();
    +  }
    +
    +  /**
    +   * Returns an iterator over the keys and values in this map.
    +   *
    +   * For efficiency, each call returns the same object.
    +   */
    +  public Iterator<MapEntry> iterator() {
    +    return new Iterator<MapEntry>() {
    +
    +      private final MapEntry entry = new MapEntry();
    +      private final Iterator<BytesToBytesMap.Location> mapLocationIterator = map.iterator();
    +
    +      @Override
    +      public boolean hasNext() {
    +        return mapLocationIterator.hasNext();
    +      }
    +
    +      @Override
    +      public MapEntry next() {
    +        final BytesToBytesMap.Location loc = mapLocationIterator.next();
    +        final MemoryLocation keyAddress = loc.getKeyAddress();
    +        final MemoryLocation valueAddress = loc.getValueAddress();
    +        entry.key.pointTo(
    +          keyAddress.getBaseObject(),
    +          keyAddress.getBaseOffset(),
    +          groupingKeySchema.length(),
    +          groupingKeySchema
    +        );
    +        entry.value.pointTo(
    +          valueAddress.getBaseObject(),
    +          valueAddress.getBaseOffset(),
    +          aggregationBufferSchema.length(),
    +          aggregationBufferSchema
    +        );
    +        return entry;
    +      }
    +
    +      @Override
    +      public void remove() {
    +        throw new UnsupportedOperationException();
    +      }
    +    };
    +  }
    +
    +  /**
    +   * Free the unsafe memory associated with this map.
    +   */
    +  public void free() {
    +    map.free();
    +  }
    +
    +  @SuppressWarnings("UseOfSystemOutOrSystemErr")
    +  public void printPerfMetrics() {
    +    if (!enablePerfMetrics) {
    +      throw new IllegalStateException("Perf metrics not enabled");
    +    }
    +    System.out.println("Average probes per lookup: " + map.getAverageProbesPerLookup());
    +    System.out.println("Number of hash collisions: " + map.getNumHashCollisions());
    +    System.out.println("Time spent resizing (ms): " + map.getTimeSpentResizingMs());
    --- End diff --
    
    ms -> ns


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org


[GitHub] spark pull request: [SPARK-7076][SPARK-7077][SPARK-7080][SQL] Use ...

Posted by JoshRosen <gi...@git.apache.org>.
Github user JoshRosen commented on the pull request:

    https://github.com/apache/spark/pull/5725#issuecomment-97915047
  
    @vanzin There's an old JIRA for building w/ Java 6 on Jenkins; I've re-opened it: https://issues.apache.org/jira/browse/SPARK-1437


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org
For additional commands, e-mail: reviews-help@spark.apache.org