You are viewing a plain text version of this content. The canonical link for it is here.
Posted to reviews@spark.apache.org by GitBox <gi...@apache.org> on 2021/06/23 08:05:27 UTC

[GitHub] [spark] HeartSaVioR opened a new pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

HeartSaVioR opened a new pull request #33038:
URL: https://github.com/apache/spark/pull/33038


   ### What changes were proposed in this pull request?
   
   This PR proposes to introduce a new feature "prefix match scan" on state store, which enables users of state store (mostly stateful operators) to group the keys into logical groups, and scan the keys in the same group efficiently.
   
   This PR will bring the API changes, though it's more likely developer API.
   
   * Registering the prefix key
   
   We propose to make an explicit change to the init() method of StateStoreProvider, as below:
   
   ```
   def init(
         stateStoreId: StateStoreId,
         keySchema: StructType,
         valueSchema: StructType,
         numColsPrefixKey: Int,
         storeConfs: StateStoreConf,
         hadoopConf: Configuration): Unit
   ```
   
   Please note that we remove an unused parameter “keyIndexOrdinal” as well. The parameter is coupled with getRange() which we will remove as well. See below for rationalization.
   
   Here we provide the number of columns we take to project the prefix key from the full key. If the operator doesn’t leverage prefix match scan, the value can (and should) be 0, because the state store provider may optimize the underlying storage format which may bring extra overhead.
   
   We would like to apply some restrictions on prefix key to simplify the functionality:
   
   * Prefix key is a part of the full key. It can’t be the same as the full key.
     * That said, the full key will be the (prefix key + remaining parts), and both prefix key and remaining parts should have at least one column.
   * We always take the columns from the leftmost sequentially, like “seq.take(nums)”.
   * We don’t allow reordering of the columns.
   * We only guarantee “equality” comparison against prefix keys, and don’t support the prefix “range” scan.
     * We only support scanning on the keys which match with the prefix key.
     * E.g. We don’t support the range scan from user A to user B due to technical complexity. That’s the reason we can’t leverage the existing getRange API.
   
   As we mentioned, we want to make an explicit change to the init() method of StateStoreProvider which would break backward compatibility, assuming that 3rd party state store providers need to update their code in any way to support prefix match scan. Given RocksDB state store provider is being donated to the OSS and plan to be available in Spark 3.2, the majority of the users would migrate to the built-in state store providers, which would remedy the concerns.
   
   * Scanning key-value pairs matched to the prefix key
   
   We propose to add a new method to the ReadStateStore (and StateStore by inheritance), as below:
   
   ```
   def prefixScan(prefixKey: UnsafeRow): Iterator[UnsafeRowPair]
   ```
   
   We require callers to pass the `prefixKey` which would have the same schema with the registered prefix key schema. In other words, the schema of the parameter `prefixKey` should match to the projection of the prefix key on the full key based on the number of columns for the prefix key.
   
   The method contract is clear - the method will return the iterator which will give the key-value pairs whose prefix key is matched with the given prefix key. Callers should only rely on the contract and should not expect any other characteristics based on specific details on the state store provider.
   
   In the caller’s point of view, the prefix key is only used for retrieving key-value pairs via prefix match scan. Callers should keep using the full key to do CRUD.
   
   Note that this PR also proposes to make a breaking change, removal of getRange(), which is never be implemented properly and hence never be called properly.
   
   ### Why are the changes needed?
   
   * Introducing prefix match scan feature
   
   Currently, the API in state store is only based on key-value data structure. This lacks on advanced data structures like list-like one, which required us to implement the data structure on our own whenever we need it. We had one in stream-stream join, and we were about to have another one in native session window. The custom implementation of data structure based on the state store API tends to be complicated and has to deal with multiple state stores.
   
   We decided to enhance the state store API a bit to remove the requirement for native session window to implement its own. From the operator of native session window, it will just need to do prefix scan on group key to retrieve all sessions belonging to the group key.
   
   Thanks to adding the feature to the part of state store API, this would enable state store providers to optimize the implementation based on the characteristic. (e.g. We will implement this in RocksDB state store provider via leveraging the characteristic that RocksDB sorts the key by natural order of binary format.)
   
   * Removal of getRange API
   
   Before introducing this we sought the way to leverage getRange, but it's quite hard to implement efficiently, with respecting its method contract. Spark always calls the method with (None, None) parameter and all the state store providers (including built-in) implement it as just calling iterator(), which is not respecting the method contract. That said, we can replace all getRange() usages to iterator(), and remove the API to remove any confusions/concerns.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes for the end users & maintainers of 3rd party state store provider. They will need to upgrade their state store provider implementations to adopt this change.
   
   ### How was this patch tested?
   
   Added UT, and also existing UTs to make sure it doesn't break anything.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871866354


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/44984/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876808311


   Weird, it passed locally. May need to add some log message to see what is happening.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] viirya closed pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
viirya closed pull request #33038:
URL: https://github.com/apache/spark/pull/33038


   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876563278


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/45320/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667566548



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/StateStore.scala
##########
@@ -251,16 +250,15 @@ trait StateStoreProvider {
    * @param stateStoreId Id of the versioned StateStores that this provider will generate
    * @param keySchema Schema of keys to be stored
    * @param valueSchema Schema of value to be stored
-   * @param keyIndexOrdinal Optional column (represent as the ordinal of the field in keySchema) by
-   *                        which the StateStore implementation could index the data.
+   * @param numColsPrefixKey The number of leftmost columns to be used as prefix key.

Review comment:
       Thanks for the input! I agree we'd need to add more details.
   
   One thing we may want to consider is that caller defines the prefix key, and it's natural (or we can document the behavior to `prefixScan` method doc) that it won't work if there's no prefix key.
   
   I feel we can just emphasize the behavior when the number is less than 1. I'll update the doc, and let's see whether it's good for you as well or not.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876469515






-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876863871


   I've addressed with RocksDB state store provider as well.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871821101


   **[Test build #140470 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140470/testReport)** for PR 33038 at commit [`36cdeab`](https://github.com/apache/spark/commit/36cdeab1483d3ac4d1e015f3ebf8d80f2148bb8a).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866838670


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140192/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-868470455


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140312/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871873522


   cc. @viirya as well. I forgot to mention.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r661889937



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/HDFSBackedStateStoreProvider.scala
##########
@@ -252,6 +238,12 @@ private[state] class HDFSBackedStateStoreProvider extends StateStoreProvider wit
     this.storeConf = storeConf
     this.hadoopConf = hadoopConf
     this.numberOfVersionsToRetainInMemory = storeConf.maxVersionsToRetainInMemory
+
+    require((keySchema.length == 0 && numColsPrefixKey == 0) ||

Review comment:
       Passing empty key schema is possible via groupBy with no column - I also noticed this in existing UT.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876447728


   Kubernetes integration test status success
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45313/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866688067


   Kubernetes integration test starting
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/44719/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] viirya commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
viirya commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667580175



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBStateEncoder.scala
##########
@@ -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.execution.streaming.state
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, JoinedRow, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider.{STATE_ENCODING_NUM_VERSION_BYTES, STATE_ENCODING_VERSION}
+import org.apache.spark.sql.types.{StructField, StructType}
+import org.apache.spark.unsafe.Platform
+
+sealed trait RocksDBStateEncoder {
+  def supportPrefixKeyScan: Boolean
+  def decodePrefixKey(groupKey: UnsafeRow): Array[Byte]
+  def extractPrefixKey(key: UnsafeRow): UnsafeRow
+
+  def encodeKey(row: UnsafeRow): Array[Byte]
+  def encodeValue(row: UnsafeRow): Array[Byte]
+
+  def decodeKey(keyBytes: Array[Byte]): UnsafeRow
+  def decodeValue(valueBytes: Array[Byte]): UnsafeRow
+  def decode(byteArrayTuple: ByteArrayPair): UnsafeRowPair
+}
+
+object RocksDBStateEncoder {
+  def getEncoder(
+      keySchema: StructType,
+      valueSchema: StructType,
+      numColsPrefixKey: Int): RocksDBStateEncoder = {
+    if (numColsPrefixKey > 0) {
+      new PrefixKeyScanStateEncoder(keySchema, valueSchema, numColsPrefixKey)
+    } else {
+      new NoPrefixKeyStateEncoder(keySchema, valueSchema)
+    }
+  }
+
+  /**
+   * Encode the UnsafeRow of N bytes as a N+1 byte array.
+   * @note This creates a new byte array and memcopies the UnsafeRow to the new array.
+   */
+  def encodeUnsafeRow(row: UnsafeRow): Array[Byte] = {
+    val bytesToEncode = row.getBytes
+    val encodedBytes = new Array[Byte](bytesToEncode.length + STATE_ENCODING_NUM_VERSION_BYTES)
+    Platform.putByte(encodedBytes, Platform.BYTE_ARRAY_OFFSET, STATE_ENCODING_VERSION)
+    // Platform.BYTE_ARRAY_OFFSET is the recommended way to memcopy b/w byte arrays. See Platform.
+    Platform.copyMemory(
+      bytesToEncode, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+      bytesToEncode.length)
+    encodedBytes
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], numFields: Int): UnsafeRow = {
+    if (bytes != null) {
+      val row = new UnsafeRow(numFields)
+      decodeToUnsafeRow(bytes, row)
+    } else {
+      null
+    }
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], reusedRow: UnsafeRow): UnsafeRow = {
+    if (bytes != null) {
+      // Platform.BYTE_ARRAY_OFFSET is the recommended way refer to the 1st offset. See Platform.
+      reusedRow.pointTo(
+        bytes,
+        Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+        bytes.length - STATE_ENCODING_NUM_VERSION_BYTES)
+      reusedRow
+    } else {
+      null
+    }
+  }
+}
+
+class PrefixKeyScanStateEncoder(
+    keySchema: StructType,
+    valueSchema: StructType,
+    numColsPrefixKey: Int) extends RocksDBStateEncoder {
+
+  import RocksDBStateEncoder._
+
+  require(keySchema.length > numColsPrefixKey, "The number of columns for prefix key must be " +
+    "greater than the number of columns in the key!")
+
+  private val groupKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.take(numColsPrefixKey)
+  }
+
+  private val remainingKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.drop(numColsPrefixKey)
+  }
+
+  private val prefixKeyProjection: UnsafeProjection = {
+    val refs = groupKeyFieldsWithIdx.map(x => BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  private val remainingKeyProjection: UnsafeProjection = {
+    val refs = remainingKeyFieldsWithIdx.map(x =>
+      BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  // This is quite simple to do - just bind sequentially, as we don't change the order.
+  private val restoreKeyProjection: UnsafeProjection = UnsafeProjection.create(keySchema)
+
+  // Reusable objects
+  private val joinedRowOnKey = new JoinedRow()
+  private val valueRow = new UnsafeRow(valueSchema.size)
+  private val rowTuple = new UnsafeRowPair()
+
+  override def encodeKey(row: UnsafeRow): Array[Byte] = {
+    val prefixKeyEncoded = encodeUnsafeRow(extractPrefixKey(row))
+    val remainingEncoded = encodeUnsafeRow(remainingKeyProjection(row))
+
+    val encodedBytes = new Array[Byte](prefixKeyEncoded.length + remainingEncoded.length + 4)
+    Platform.putInt(encodedBytes, Platform.BYTE_ARRAY_OFFSET, prefixKeyEncoded.length)
+    Platform.copyMemory(prefixKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4, prefixKeyEncoded.length)
+    // NOTE: We don't put the length of remainingEncoded as we can calculate later
+    // on deserialization.
+    Platform.copyMemory(remainingEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4 + prefixKeyEncoded.length,
+      remainingEncoded.length)
+
+    encodedBytes
+  }
+
+  override def encodeValue(row: UnsafeRow): Array[Byte] = encodeUnsafeRow(row)
+
+  override def decodeKey(keyBytes: Array[Byte]): UnsafeRow = {
+    val groupKeyEncodedLen = Platform.getInt(keyBytes, Platform.BYTE_ARRAY_OFFSET)
+    val groupKeyEncoded = new Array[Byte](groupKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4, groupKeyEncoded,
+      Platform.BYTE_ARRAY_OFFSET, groupKeyEncodedLen)
+
+    // Here we calculate the remainingKeyEncodedLen leveraging the length of keyBytes
+    val remainingKeyEncodedLen = keyBytes.length - 4 - groupKeyEncodedLen
+
+    val remainingKeyEncoded = new Array[Byte](remainingKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4 +
+      groupKeyEncodedLen, remainingKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      remainingKeyEncodedLen)
+
+    val groupKeyDecoded = decodeToUnsafeRow(groupKeyEncoded, groupKeyFieldsWithIdx.length)
+    val remainingKeyDecoded = decodeToUnsafeRow(remainingKeyEncoded, numFields = 1)
+
+    restoreKeyProjection(joinedRowOnKey.withLeft(groupKeyDecoded).withRight(remainingKeyDecoded))
+  }
+
+  override def decodeValue(valueBytes: Array[Byte]): UnsafeRow = {
+    decodeToUnsafeRow(valueBytes, valueRow)
+  }
+
+  override def extractPrefixKey(key: UnsafeRow): UnsafeRow = {
+    prefixKeyProjection(key)
+  }
+
+  override def decodePrefixKey(groupKey: UnsafeRow): Array[Byte] = {

Review comment:
       Because among `RocksDBStateEncoder`'s methods, decode methods (e.g., `decodeKey` and `decodeValue`) take bytes (`Array[Byte]`) and return `UnsafeRow`. Encode methods (e.g., `encodeKey` and `encodeValue`) take `UnsafeRow` and return bytes.
   
   This method takes an `UnsafeRow` and returns bytes. So it looks like `encodePrefixKey` instead of `decodePrefixKey`?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667570880



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/StateStore.scala
##########
@@ -60,21 +60,17 @@ trait ReadStateStore {
   def get(key: UnsafeRow): UnsafeRow
 
   /**
-   * Get key value pairs with optional approximate `start` and `end` extents.
-   * If the State Store implementation maintains indices for the data based on the optional
-   * `keyIndexOrdinal` over fields `keySchema` (see `StateStoreProvider.init()`), then it can use
-   * `start` and `end` to make a best-effort scan over the data. Default implementation returns
-   * the full data scan iterator, which is correct but inefficient. Custom implementations must
-   * ensure that updates (puts, removes) can be made while iterating over this iterator.
+   * Return an iterator containing all the key-value pairs which are matched with
+   * the given prefix key.
+   *
+   * Spark will provide numColsPrefixKey greater than 0 in StateStoreProvider.init method if
+   * the state store is responsible to handle the request for prefix scan. The schema of the
+   * prefix key should be same with the leftmost `numColsPrefixKey` columns of the key schema.
    *
-   * @param start UnsafeRow having the `keyIndexOrdinal` column set with appropriate starting value.
-   * @param end UnsafeRow having the `keyIndexOrdinal` column set with appropriate ending value.
-   * @return An iterator of key-value pairs that is guaranteed not miss any key between start and
-   *         end, both inclusive.
+   * It is expected to throw exception if Spark calls this method without setting numColsPrefixKey
+   * to the greater than 0.
    */
-  def getRange(start: Option[UnsafeRow], end: Option[UnsafeRow]): Iterator[UnsafeRowPair] = {
-    iterator()
-  }
+  def prefixScan(prefixKey: UnsafeRow): Iterator[UnsafeRowPair]

Review comment:
       MemoryStateStore is for test purpose. I just skipped implementing it as there's no usage of prefix scan against MemoryStateStore. We can add it whenever we need, like the case we start to feel it'd be easier to test the prefix scan against MemoryStateStore.
   
   For 3rd party implementations, I'd say it is necessary to support prefix scan to continue supporting further Spark version. They can still use the trick that throwing exception and saying "this state store provider doesn't support session window", but I'd rather not say the feature is limited to session window in the future, hence it would be eventually no longer true and more and more things cannot be supported by such state store providers.
   
   In the documentation we can guide the trick and what will happen with the trick, but we probably couldn't update the doc every time for which functionalities will break if prefix scan is not supported. If we still want to allow 3rd party implementations to support partial features, I'll add a guide in the doc.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876386415


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140801/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR edited a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR edited a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871873522


   cc. @viirya as well. Sorry I forgot to mention.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-877945186


   Kubernetes integration test status success
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45402/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866722968


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/44719/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-868295849


   **[Test build #140312 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140312/testReport)** for PR 33038 at commit [`cee9c3c`](https://github.com/apache/spark/commit/cee9c3cab32b14b3723f1801307c49def7949fdb).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876859315


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/45337/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876847262


   Kubernetes integration test status success
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45337/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876386415


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140801/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-868372618


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/44844/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876519556


   **[Test build #140809 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140809/testReport)** for PR 33038 at commit [`b2eaf3a`](https://github.com/apache/spark/commit/b2eaf3ac197ee6423980b1e143e38ad32eb3c3ce).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876433018


   Kubernetes integration test starting
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45314/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] viirya commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
viirya commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878404420


   Thanks. Merging to master/3.2.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-877989099


   **[Test build #140891 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140891/testReport)** for PR 33038 at commit [`8b2f945`](https://github.com/apache/spark/commit/8b2f945537afbb6fed63c19f621b0cbe439c3a1b).
    * This patch **fails Spark unit tests**.
    * This patch merges cleanly.
    * This patch adds no public classes.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r661894685



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/HDFSBackedStateStoreMap.scala
##########
@@ -0,0 +1,172 @@
+/*
+ * 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.execution.streaming.state
+
+import scala.collection.JavaConverters._
+import scala.collection.mutable
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.types.{StructField, StructType}
+
+trait HDFSBackedStateStoreMap {
+  def size(): Int
+  def get(key: UnsafeRow): UnsafeRow
+  def put(key: UnsafeRow, value: UnsafeRow): UnsafeRow
+  def putAll(map: HDFSBackedStateStoreMap): Unit
+  def remove(key: UnsafeRow): UnsafeRow
+  def iterator(): Iterator[UnsafeRowPair]
+  def prefixScan(prefixKey: UnsafeRow): Iterator[UnsafeRowPair]
+  def clear(): Unit
+}
+
+object HDFSBackedStateStoreMap {
+  def create(keySchema: StructType, numColsPrefixKey: Int): HDFSBackedStateStoreMap = {
+    if (numColsPrefixKey > 0) {
+      new PrefixScannableHDFSBackedStateStoreMap(keySchema, numColsPrefixKey)
+    } else {
+      new NoPrefixHDFSBackedStateStoreMap()
+    }
+  }
+}
+
+class NoPrefixHDFSBackedStateStoreMap extends HDFSBackedStateStoreMap {
+  // ConcurrentHashMap is used because it generates fail-safe iterators on filtering
+  // - The iterator is weakly consistent with the map, i.e., iterator's data reflect the values in
+  //   the map when the iterator was created
+  // - Any updates to the map while iterating through the filtered iterator does not throw
+  //   java.util.ConcurrentModificationException
+  private val map = new java.util.concurrent.ConcurrentHashMap[UnsafeRow, UnsafeRow]()

Review comment:
       Thinking a bit more, I think the type is now bound to the `HDFSBackedStateStoreMap` instead of `HDFSBackedStateStoreProvider` and moving the type definition to object `HDFSBackedStateStoreMap` would deduplicate the code with retaining high cohesion. I'll do this instead.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871866354


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/44984/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871849227


   Kubernetes integration test status success
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/44984/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-873008369


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140569/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871923225


   **[Test build #140470 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140470/testReport)** for PR 33038 at commit [`36cdeab`](https://github.com/apache/spark/commit/36cdeab1483d3ac4d1e015f3ebf8d80f2148bb8a).
    * This patch passes all tests.
    * This patch merges cleanly.
    * This patch adds no public classes.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-868361047


   Kubernetes integration test status success
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/44844/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876384664


   **[Test build #140801 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140801/testReport)** for PR 33038 at commit [`4847dc2`](https://github.com/apache/spark/commit/4847dc2a5030f6356a22fba08eebdd7c32984227).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876394143


   **[Test build #140802 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140802/testReport)** for PR 33038 at commit [`556662a`](https://github.com/apache/spark/commit/556662a493f96bee3925b42c312e9d82cbd20aa6).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876519556


   **[Test build #140809 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140809/testReport)** for PR 33038 at commit [`b2eaf3a`](https://github.com/apache/spark/commit/b2eaf3ac197ee6423980b1e143e38ad32eb3c3ce).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876517602


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140802/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-877934422


   Kubernetes integration test starting
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45402/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876859315


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/45337/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-868462757


   **[Test build #140312 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140312/testReport)** for PR 33038 at commit [`cee9c3c`](https://github.com/apache/spark/commit/cee9c3cab32b14b3723f1801307c49def7949fdb).
    * This patch passes all tests.
    * This patch merges cleanly.
    * This patch adds no public classes.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-868372618


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/44844/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876917578


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140826/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876808311


   Weird, it passed locally. May need to add some log message to see what is happening.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876394143


   **[Test build #140802 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140802/testReport)** for PR 33038 at commit [`556662a`](https://github.com/apache/spark/commit/556662a493f96bee3925b42c312e9d82cbd20aa6).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR edited a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR edited a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878042883


   Thanks for reviewing, @viirya and @xuanyuanking  ! I'll rebase the next PR once you merge this PR.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667582088



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBStateEncoder.scala
##########
@@ -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.execution.streaming.state
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, JoinedRow, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider.{STATE_ENCODING_NUM_VERSION_BYTES, STATE_ENCODING_VERSION}
+import org.apache.spark.sql.types.{StructField, StructType}
+import org.apache.spark.unsafe.Platform
+
+sealed trait RocksDBStateEncoder {
+  def supportPrefixKeyScan: Boolean
+  def decodePrefixKey(groupKey: UnsafeRow): Array[Byte]
+  def extractPrefixKey(key: UnsafeRow): UnsafeRow
+
+  def encodeKey(row: UnsafeRow): Array[Byte]
+  def encodeValue(row: UnsafeRow): Array[Byte]
+
+  def decodeKey(keyBytes: Array[Byte]): UnsafeRow
+  def decodeValue(valueBytes: Array[Byte]): UnsafeRow
+  def decode(byteArrayTuple: ByteArrayPair): UnsafeRowPair
+}
+
+object RocksDBStateEncoder {
+  def getEncoder(
+      keySchema: StructType,
+      valueSchema: StructType,
+      numColsPrefixKey: Int): RocksDBStateEncoder = {
+    if (numColsPrefixKey > 0) {
+      new PrefixKeyScanStateEncoder(keySchema, valueSchema, numColsPrefixKey)
+    } else {
+      new NoPrefixKeyStateEncoder(keySchema, valueSchema)
+    }
+  }
+
+  /**
+   * Encode the UnsafeRow of N bytes as a N+1 byte array.
+   * @note This creates a new byte array and memcopies the UnsafeRow to the new array.
+   */
+  def encodeUnsafeRow(row: UnsafeRow): Array[Byte] = {
+    val bytesToEncode = row.getBytes
+    val encodedBytes = new Array[Byte](bytesToEncode.length + STATE_ENCODING_NUM_VERSION_BYTES)
+    Platform.putByte(encodedBytes, Platform.BYTE_ARRAY_OFFSET, STATE_ENCODING_VERSION)
+    // Platform.BYTE_ARRAY_OFFSET is the recommended way to memcopy b/w byte arrays. See Platform.
+    Platform.copyMemory(
+      bytesToEncode, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+      bytesToEncode.length)
+    encodedBytes
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], numFields: Int): UnsafeRow = {
+    if (bytes != null) {
+      val row = new UnsafeRow(numFields)
+      decodeToUnsafeRow(bytes, row)
+    } else {
+      null
+    }
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], reusedRow: UnsafeRow): UnsafeRow = {
+    if (bytes != null) {
+      // Platform.BYTE_ARRAY_OFFSET is the recommended way refer to the 1st offset. See Platform.
+      reusedRow.pointTo(
+        bytes,
+        Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+        bytes.length - STATE_ENCODING_NUM_VERSION_BYTES)
+      reusedRow
+    } else {
+      null
+    }
+  }
+}
+
+class PrefixKeyScanStateEncoder(
+    keySchema: StructType,
+    valueSchema: StructType,
+    numColsPrefixKey: Int) extends RocksDBStateEncoder {
+
+  import RocksDBStateEncoder._
+
+  require(keySchema.length > numColsPrefixKey, "The number of columns for prefix key must be " +
+    "greater than the number of columns in the key!")
+
+  private val groupKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.take(numColsPrefixKey)
+  }
+
+  private val remainingKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.drop(numColsPrefixKey)
+  }
+
+  private val prefixKeyProjection: UnsafeProjection = {
+    val refs = groupKeyFieldsWithIdx.map(x => BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  private val remainingKeyProjection: UnsafeProjection = {
+    val refs = remainingKeyFieldsWithIdx.map(x =>
+      BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  // This is quite simple to do - just bind sequentially, as we don't change the order.
+  private val restoreKeyProjection: UnsafeProjection = UnsafeProjection.create(keySchema)
+
+  // Reusable objects
+  private val joinedRowOnKey = new JoinedRow()
+  private val valueRow = new UnsafeRow(valueSchema.size)
+  private val rowTuple = new UnsafeRowPair()
+
+  override def encodeKey(row: UnsafeRow): Array[Byte] = {
+    val prefixKeyEncoded = encodeUnsafeRow(extractPrefixKey(row))
+    val remainingEncoded = encodeUnsafeRow(remainingKeyProjection(row))
+
+    val encodedBytes = new Array[Byte](prefixKeyEncoded.length + remainingEncoded.length + 4)
+    Platform.putInt(encodedBytes, Platform.BYTE_ARRAY_OFFSET, prefixKeyEncoded.length)
+    Platform.copyMemory(prefixKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4, prefixKeyEncoded.length)
+    // NOTE: We don't put the length of remainingEncoded as we can calculate later
+    // on deserialization.
+    Platform.copyMemory(remainingEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4 + prefixKeyEncoded.length,
+      remainingEncoded.length)
+
+    encodedBytes
+  }
+
+  override def encodeValue(row: UnsafeRow): Array[Byte] = encodeUnsafeRow(row)
+
+  override def decodeKey(keyBytes: Array[Byte]): UnsafeRow = {
+    val groupKeyEncodedLen = Platform.getInt(keyBytes, Platform.BYTE_ARRAY_OFFSET)
+    val groupKeyEncoded = new Array[Byte](groupKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4, groupKeyEncoded,
+      Platform.BYTE_ARRAY_OFFSET, groupKeyEncodedLen)
+
+    // Here we calculate the remainingKeyEncodedLen leveraging the length of keyBytes
+    val remainingKeyEncodedLen = keyBytes.length - 4 - groupKeyEncodedLen
+
+    val remainingKeyEncoded = new Array[Byte](remainingKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4 +
+      groupKeyEncodedLen, remainingKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      remainingKeyEncodedLen)
+
+    val groupKeyDecoded = decodeToUnsafeRow(groupKeyEncoded, groupKeyFieldsWithIdx.length)
+    val remainingKeyDecoded = decodeToUnsafeRow(remainingKeyEncoded, numFields = 1)
+
+    restoreKeyProjection(joinedRowOnKey.withLeft(groupKeyDecoded).withRight(remainingKeyDecoded))
+  }
+
+  override def decodeValue(valueBytes: Array[Byte]): UnsafeRow = {
+    decodeToUnsafeRow(valueBytes, valueRow)
+  }
+
+  override def extractPrefixKey(key: UnsafeRow): UnsafeRow = {
+    prefixKeyProjection(key)
+  }
+
+  override def decodePrefixKey(groupKey: UnsafeRow): Array[Byte] = {

Review comment:
       Ah OK nice finding! Seems like I somehow confused at that point.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] xuanyuanking commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
xuanyuanking commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r662094639



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/HDFSBackedStateStoreProvider.scala
##########
@@ -252,6 +238,12 @@ private[state] class HDFSBackedStateStoreProvider extends StateStoreProvider wit
     this.storeConf = storeConf
     this.hadoopConf = hadoopConf
     this.numberOfVersionsToRetainInMemory = storeConf.maxVersionsToRetainInMemory
+
+    require((keySchema.length == 0 && numColsPrefixKey == 0) ||

Review comment:
       Copy that. Thanks for the explanation.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876491076


   Some relevant tests are failing; will fix and update.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-872830269


   **[Test build #140569 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140569/testReport)** for PR 33038 at commit [`ef8b767`](https://github.com/apache/spark/commit/ef8b767bc996e1d73b8fc0aaa0825b653d88ac4d).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-873008369


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140569/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871936166


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140470/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] viirya commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
viirya commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878027598


   I'll merge this tomorrow. Thanks @HeartSaVioR @xuanyuanking 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866838670


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140192/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876459103


   Kubernetes integration test status success
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45314/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-872902566


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/45081/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-872858582


   Kubernetes integration test starting
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45081/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-872830269


   **[Test build #140569 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140569/testReport)** for PR 33038 at commit [`ef8b767`](https://github.com/apache/spark/commit/ef8b767bc996e1d73b8fc0aaa0825b653d88ac4d).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878000011






-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878130594


   retest this, please


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876917578


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140826/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876553299


   Kubernetes integration test unable to build dist.
   
   exiting with code: 1
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45320/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-877921683


   **[Test build #140891 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140891/testReport)** for PR 33038 at commit [`8b2f945`](https://github.com/apache/spark/commit/8b2f945537afbb6fed63c19f621b0cbe439c3a1b).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] xuanyuanking commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
xuanyuanking commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r661517930



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/HDFSBackedStateStoreMap.scala
##########
@@ -0,0 +1,172 @@
+/*
+ * 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.execution.streaming.state
+
+import scala.collection.JavaConverters._
+import scala.collection.mutable
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.types.{StructField, StructType}
+
+trait HDFSBackedStateStoreMap {
+  def size(): Int
+  def get(key: UnsafeRow): UnsafeRow
+  def put(key: UnsafeRow, value: UnsafeRow): UnsafeRow
+  def putAll(map: HDFSBackedStateStoreMap): Unit
+  def remove(key: UnsafeRow): UnsafeRow
+  def iterator(): Iterator[UnsafeRowPair]
+  def prefixScan(prefixKey: UnsafeRow): Iterator[UnsafeRowPair]
+  def clear(): Unit
+}
+
+object HDFSBackedStateStoreMap {
+  def create(keySchema: StructType, numColsPrefixKey: Int): HDFSBackedStateStoreMap = {
+    if (numColsPrefixKey > 0) {
+      new PrefixScannableHDFSBackedStateStoreMap(keySchema, numColsPrefixKey)
+    } else {
+      new NoPrefixHDFSBackedStateStoreMap()
+    }
+  }
+}
+
+class NoPrefixHDFSBackedStateStoreMap extends HDFSBackedStateStoreMap {
+  // ConcurrentHashMap is used because it generates fail-safe iterators on filtering
+  // - The iterator is weakly consistent with the map, i.e., iterator's data reflect the values in
+  //   the map when the iterator was created
+  // - Any updates to the map while iterating through the filtered iterator does not throw
+  //   java.util.ConcurrentModificationException
+  private val map = new java.util.concurrent.ConcurrentHashMap[UnsafeRow, UnsafeRow]()

Review comment:
       nit: maybe we can still keep the type definition as https://github.com/apache/spark/pull/33038/files#diff-36ad1664106a22a3f6ffabd4e3ed812201e8055dc3b5f6b116dbeb8de72baac0L79, then we can avoid copying the long comment in here and L88.

##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/HDFSBackedStateStoreProvider.scala
##########
@@ -252,6 +238,12 @@ private[state] class HDFSBackedStateStoreProvider extends StateStoreProvider wit
     this.storeConf = storeConf
     this.hadoopConf = hadoopConf
     this.numberOfVersionsToRetainInMemory = storeConf.maxVersionsToRetainInMemory
+
+    require((keySchema.length == 0 && numColsPrefixKey == 0) ||

Review comment:
       Do we accept passing an empty keySchema? Or it's just want to make the assertion safe?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878042883


   Thanks for reviewing, @viirya ! I'll rebase the next PR once you merge this PR.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878005490


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140891/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876820847


   **[Test build #140826 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140826/testReport)** for PR 33038 at commit [`a0f34b7`](https://github.com/apache/spark/commit/a0f34b77b25e32bd5002f9df5e80cdc22089a84c).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878028075


   Kubernetes integration test starting
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45411/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876469515






-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876517602


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140802/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-868330474


   Kubernetes integration test starting
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/44844/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878007045


   **[Test build #140900 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140900/testReport)** for PR 33038 at commit [`8b2f945`](https://github.com/apache/spark/commit/8b2f945537afbb6fed63c19f621b0cbe439c3a1b).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-872989989


   **[Test build #140569 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140569/testReport)** for PR 33038 at commit [`ef8b767`](https://github.com/apache/spark/commit/ef8b767bc996e1d73b8fc0aaa0825b653d88ac4d).
    * This patch passes all tests.
    * This patch merges cleanly.
    * This patch adds no public classes.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871936166


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140470/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667582088



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBStateEncoder.scala
##########
@@ -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.execution.streaming.state
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, JoinedRow, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider.{STATE_ENCODING_NUM_VERSION_BYTES, STATE_ENCODING_VERSION}
+import org.apache.spark.sql.types.{StructField, StructType}
+import org.apache.spark.unsafe.Platform
+
+sealed trait RocksDBStateEncoder {
+  def supportPrefixKeyScan: Boolean
+  def decodePrefixKey(groupKey: UnsafeRow): Array[Byte]
+  def extractPrefixKey(key: UnsafeRow): UnsafeRow
+
+  def encodeKey(row: UnsafeRow): Array[Byte]
+  def encodeValue(row: UnsafeRow): Array[Byte]
+
+  def decodeKey(keyBytes: Array[Byte]): UnsafeRow
+  def decodeValue(valueBytes: Array[Byte]): UnsafeRow
+  def decode(byteArrayTuple: ByteArrayPair): UnsafeRowPair
+}
+
+object RocksDBStateEncoder {
+  def getEncoder(
+      keySchema: StructType,
+      valueSchema: StructType,
+      numColsPrefixKey: Int): RocksDBStateEncoder = {
+    if (numColsPrefixKey > 0) {
+      new PrefixKeyScanStateEncoder(keySchema, valueSchema, numColsPrefixKey)
+    } else {
+      new NoPrefixKeyStateEncoder(keySchema, valueSchema)
+    }
+  }
+
+  /**
+   * Encode the UnsafeRow of N bytes as a N+1 byte array.
+   * @note This creates a new byte array and memcopies the UnsafeRow to the new array.
+   */
+  def encodeUnsafeRow(row: UnsafeRow): Array[Byte] = {
+    val bytesToEncode = row.getBytes
+    val encodedBytes = new Array[Byte](bytesToEncode.length + STATE_ENCODING_NUM_VERSION_BYTES)
+    Platform.putByte(encodedBytes, Platform.BYTE_ARRAY_OFFSET, STATE_ENCODING_VERSION)
+    // Platform.BYTE_ARRAY_OFFSET is the recommended way to memcopy b/w byte arrays. See Platform.
+    Platform.copyMemory(
+      bytesToEncode, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+      bytesToEncode.length)
+    encodedBytes
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], numFields: Int): UnsafeRow = {
+    if (bytes != null) {
+      val row = new UnsafeRow(numFields)
+      decodeToUnsafeRow(bytes, row)
+    } else {
+      null
+    }
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], reusedRow: UnsafeRow): UnsafeRow = {
+    if (bytes != null) {
+      // Platform.BYTE_ARRAY_OFFSET is the recommended way refer to the 1st offset. See Platform.
+      reusedRow.pointTo(
+        bytes,
+        Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+        bytes.length - STATE_ENCODING_NUM_VERSION_BYTES)
+      reusedRow
+    } else {
+      null
+    }
+  }
+}
+
+class PrefixKeyScanStateEncoder(
+    keySchema: StructType,
+    valueSchema: StructType,
+    numColsPrefixKey: Int) extends RocksDBStateEncoder {
+
+  import RocksDBStateEncoder._
+
+  require(keySchema.length > numColsPrefixKey, "The number of columns for prefix key must be " +
+    "greater than the number of columns in the key!")
+
+  private val groupKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.take(numColsPrefixKey)
+  }
+
+  private val remainingKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.drop(numColsPrefixKey)
+  }
+
+  private val prefixKeyProjection: UnsafeProjection = {
+    val refs = groupKeyFieldsWithIdx.map(x => BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  private val remainingKeyProjection: UnsafeProjection = {
+    val refs = remainingKeyFieldsWithIdx.map(x =>
+      BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  // This is quite simple to do - just bind sequentially, as we don't change the order.
+  private val restoreKeyProjection: UnsafeProjection = UnsafeProjection.create(keySchema)
+
+  // Reusable objects
+  private val joinedRowOnKey = new JoinedRow()
+  private val valueRow = new UnsafeRow(valueSchema.size)
+  private val rowTuple = new UnsafeRowPair()
+
+  override def encodeKey(row: UnsafeRow): Array[Byte] = {
+    val prefixKeyEncoded = encodeUnsafeRow(extractPrefixKey(row))
+    val remainingEncoded = encodeUnsafeRow(remainingKeyProjection(row))
+
+    val encodedBytes = new Array[Byte](prefixKeyEncoded.length + remainingEncoded.length + 4)
+    Platform.putInt(encodedBytes, Platform.BYTE_ARRAY_OFFSET, prefixKeyEncoded.length)
+    Platform.copyMemory(prefixKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4, prefixKeyEncoded.length)
+    // NOTE: We don't put the length of remainingEncoded as we can calculate later
+    // on deserialization.
+    Platform.copyMemory(remainingEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4 + prefixKeyEncoded.length,
+      remainingEncoded.length)
+
+    encodedBytes
+  }
+
+  override def encodeValue(row: UnsafeRow): Array[Byte] = encodeUnsafeRow(row)
+
+  override def decodeKey(keyBytes: Array[Byte]): UnsafeRow = {
+    val groupKeyEncodedLen = Platform.getInt(keyBytes, Platform.BYTE_ARRAY_OFFSET)
+    val groupKeyEncoded = new Array[Byte](groupKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4, groupKeyEncoded,
+      Platform.BYTE_ARRAY_OFFSET, groupKeyEncodedLen)
+
+    // Here we calculate the remainingKeyEncodedLen leveraging the length of keyBytes
+    val remainingKeyEncodedLen = keyBytes.length - 4 - groupKeyEncodedLen
+
+    val remainingKeyEncoded = new Array[Byte](remainingKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4 +
+      groupKeyEncodedLen, remainingKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      remainingKeyEncodedLen)
+
+    val groupKeyDecoded = decodeToUnsafeRow(groupKeyEncoded, groupKeyFieldsWithIdx.length)
+    val remainingKeyDecoded = decodeToUnsafeRow(remainingKeyEncoded, numFields = 1)
+
+    restoreKeyProjection(joinedRowOnKey.withLeft(groupKeyDecoded).withRight(remainingKeyDecoded))
+  }
+
+  override def decodeValue(valueBytes: Array[Byte]): UnsafeRow = {
+    decodeToUnsafeRow(valueBytes, valueRow)
+  }
+
+  override def extractPrefixKey(key: UnsafeRow): UnsafeRow = {
+    prefixKeyProjection(key)
+  }
+
+  override def decodePrefixKey(groupKey: UnsafeRow): Array[Byte] = {

Review comment:
       Ah OK nice finding! Seems like I somehow confused at that point. Even I used `encode` in content of the method lol




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876602677


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140809/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-872878103


   Kubernetes integration test status success
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45081/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876593695


   **[Test build #140809 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140809/testReport)** for PR 33038 at commit [`b2eaf3a`](https://github.com/apache/spark/commit/b2eaf3ac197ee6423980b1e143e38ad32eb3c3ce).
    * This patch **fails Spark unit tests**.
    * This patch merges cleanly.
    * This patch adds no public classes.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876423102


   Kubernetes integration test starting
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45313/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878075967


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/45411/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876835881


   Kubernetes integration test starting
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45337/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r661889773



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/HDFSBackedStateStoreMap.scala
##########
@@ -0,0 +1,172 @@
+/*
+ * 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.execution.streaming.state
+
+import scala.collection.JavaConverters._
+import scala.collection.mutable
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.types.{StructField, StructType}
+
+trait HDFSBackedStateStoreMap {
+  def size(): Int
+  def get(key: UnsafeRow): UnsafeRow
+  def put(key: UnsafeRow, value: UnsafeRow): UnsafeRow
+  def putAll(map: HDFSBackedStateStoreMap): Unit
+  def remove(key: UnsafeRow): UnsafeRow
+  def iterator(): Iterator[UnsafeRowPair]
+  def prefixScan(prefixKey: UnsafeRow): Iterator[UnsafeRowPair]
+  def clear(): Unit
+}
+
+object HDFSBackedStateStoreMap {
+  def create(keySchema: StructType, numColsPrefixKey: Int): HDFSBackedStateStoreMap = {
+    if (numColsPrefixKey > 0) {
+      new PrefixScannableHDFSBackedStateStoreMap(keySchema, numColsPrefixKey)
+    } else {
+      new NoPrefixHDFSBackedStateStoreMap()
+    }
+  }
+}
+
+class NoPrefixHDFSBackedStateStoreMap extends HDFSBackedStateStoreMap {
+  // ConcurrentHashMap is used because it generates fail-safe iterators on filtering
+  // - The iterator is weakly consistent with the map, i.e., iterator's data reflect the values in
+  //   the map when the iterator was created
+  // - Any updates to the map while iterating through the filtered iterator does not throw
+  //   java.util.ConcurrentModificationException
+  private val map = new java.util.concurrent.ConcurrentHashMap[UnsafeRow, UnsafeRow]()

Review comment:
       No big deal. I'll revert this one.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-877958525


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/45402/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876386389


   **[Test build #140801 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140801/testReport)** for PR 33038 at commit [`4847dc2`](https://github.com/apache/spark/commit/4847dc2a5030f6356a22fba08eebdd7c32984227).
    * This patch **fails Scala style tests**.
    * This patch merges cleanly.
    * This patch adds the following public classes _(experimental)_:
     * `trait HDFSBackedStateStoreMap `
     * `class NoPrefixHDFSBackedStateStoreMap extends HDFSBackedStateStoreMap `
     * `class PrefixScannableHDFSBackedStateStoreMap(`
     * `  class HDFSBackedReadStateStore(val version: Long, map: HDFSBackedStateStoreMap)`
     * `  class HDFSBackedStateStore(val version: Long, mapToUpdate: HDFSBackedStateStoreMap)`
     * `sealed trait RocksDBStateEncoder `
     * `class PrefixKeyScanStateEncoder(`
     * `class NoPrefixKeyStateEncoder(keySchema: StructType, valueSchema: StructType)`


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667571770



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBStateEncoder.scala
##########
@@ -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.execution.streaming.state
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, JoinedRow, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider.{STATE_ENCODING_NUM_VERSION_BYTES, STATE_ENCODING_VERSION}
+import org.apache.spark.sql.types.{StructField, StructType}
+import org.apache.spark.unsafe.Platform
+
+sealed trait RocksDBStateEncoder {
+  def supportPrefixKeyScan: Boolean
+  def decodePrefixKey(groupKey: UnsafeRow): Array[Byte]
+  def extractPrefixKey(key: UnsafeRow): UnsafeRow
+
+  def encodeKey(row: UnsafeRow): Array[Byte]
+  def encodeValue(row: UnsafeRow): Array[Byte]
+
+  def decodeKey(keyBytes: Array[Byte]): UnsafeRow
+  def decodeValue(valueBytes: Array[Byte]): UnsafeRow
+  def decode(byteArrayTuple: ByteArrayPair): UnsafeRowPair
+}
+
+object RocksDBStateEncoder {
+  def getEncoder(
+      keySchema: StructType,
+      valueSchema: StructType,
+      numColsPrefixKey: Int): RocksDBStateEncoder = {
+    if (numColsPrefixKey > 0) {
+      new PrefixKeyScanStateEncoder(keySchema, valueSchema, numColsPrefixKey)
+    } else {
+      new NoPrefixKeyStateEncoder(keySchema, valueSchema)
+    }
+  }
+
+  /**
+   * Encode the UnsafeRow of N bytes as a N+1 byte array.
+   * @note This creates a new byte array and memcopies the UnsafeRow to the new array.
+   */
+  def encodeUnsafeRow(row: UnsafeRow): Array[Byte] = {
+    val bytesToEncode = row.getBytes
+    val encodedBytes = new Array[Byte](bytesToEncode.length + STATE_ENCODING_NUM_VERSION_BYTES)
+    Platform.putByte(encodedBytes, Platform.BYTE_ARRAY_OFFSET, STATE_ENCODING_VERSION)
+    // Platform.BYTE_ARRAY_OFFSET is the recommended way to memcopy b/w byte arrays. See Platform.
+    Platform.copyMemory(
+      bytesToEncode, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+      bytesToEncode.length)
+    encodedBytes
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], numFields: Int): UnsafeRow = {
+    if (bytes != null) {
+      val row = new UnsafeRow(numFields)
+      decodeToUnsafeRow(bytes, row)
+    } else {
+      null
+    }
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], reusedRow: UnsafeRow): UnsafeRow = {
+    if (bytes != null) {
+      // Platform.BYTE_ARRAY_OFFSET is the recommended way refer to the 1st offset. See Platform.
+      reusedRow.pointTo(
+        bytes,
+        Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+        bytes.length - STATE_ENCODING_NUM_VERSION_BYTES)
+      reusedRow
+    } else {
+      null
+    }
+  }
+}
+
+class PrefixKeyScanStateEncoder(
+    keySchema: StructType,
+    valueSchema: StructType,
+    numColsPrefixKey: Int) extends RocksDBStateEncoder {
+
+  import RocksDBStateEncoder._
+
+  require(keySchema.length > numColsPrefixKey, "The number of columns for prefix key must be " +
+    "greater than the number of columns in the key!")
+
+  private val groupKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.take(numColsPrefixKey)
+  }
+
+  private val remainingKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.drop(numColsPrefixKey)
+  }
+
+  private val prefixKeyProjection: UnsafeProjection = {
+    val refs = groupKeyFieldsWithIdx.map(x => BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  private val remainingKeyProjection: UnsafeProjection = {
+    val refs = remainingKeyFieldsWithIdx.map(x =>
+      BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  // This is quite simple to do - just bind sequentially, as we don't change the order.
+  private val restoreKeyProjection: UnsafeProjection = UnsafeProjection.create(keySchema)
+
+  // Reusable objects
+  private val joinedRowOnKey = new JoinedRow()
+  private val valueRow = new UnsafeRow(valueSchema.size)
+  private val rowTuple = new UnsafeRowPair()
+
+  override def encodeKey(row: UnsafeRow): Array[Byte] = {
+    val prefixKeyEncoded = encodeUnsafeRow(extractPrefixKey(row))
+    val remainingEncoded = encodeUnsafeRow(remainingKeyProjection(row))
+
+    val encodedBytes = new Array[Byte](prefixKeyEncoded.length + remainingEncoded.length + 4)
+    Platform.putInt(encodedBytes, Platform.BYTE_ARRAY_OFFSET, prefixKeyEncoded.length)
+    Platform.copyMemory(prefixKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4, prefixKeyEncoded.length)
+    // NOTE: We don't put the length of remainingEncoded as we can calculate later
+    // on deserialization.
+    Platform.copyMemory(remainingEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4 + prefixKeyEncoded.length,
+      remainingEncoded.length)
+
+    encodedBytes
+  }
+
+  override def encodeValue(row: UnsafeRow): Array[Byte] = encodeUnsafeRow(row)
+
+  override def decodeKey(keyBytes: Array[Byte]): UnsafeRow = {
+    val groupKeyEncodedLen = Platform.getInt(keyBytes, Platform.BYTE_ARRAY_OFFSET)
+    val groupKeyEncoded = new Array[Byte](groupKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4, groupKeyEncoded,
+      Platform.BYTE_ARRAY_OFFSET, groupKeyEncodedLen)
+
+    // Here we calculate the remainingKeyEncodedLen leveraging the length of keyBytes
+    val remainingKeyEncodedLen = keyBytes.length - 4 - groupKeyEncodedLen
+
+    val remainingKeyEncoded = new Array[Byte](remainingKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4 +
+      groupKeyEncodedLen, remainingKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      remainingKeyEncodedLen)
+
+    val groupKeyDecoded = decodeToUnsafeRow(groupKeyEncoded, groupKeyFieldsWithIdx.length)
+    val remainingKeyDecoded = decodeToUnsafeRow(remainingKeyEncoded, numFields = 1)
+
+    restoreKeyProjection(joinedRowOnKey.withLeft(groupKeyDecoded).withRight(remainingKeyDecoded))
+  }
+
+  override def decodeValue(valueBytes: Array[Byte]): UnsafeRow = {
+    decodeToUnsafeRow(valueBytes, valueRow)
+  }
+
+  override def extractPrefixKey(key: UnsafeRow): UnsafeRow = {
+    prefixKeyProjection(key)
+  }
+
+  override def decodePrefixKey(groupKey: UnsafeRow): Array[Byte] = {

Review comment:
       Could you please elaborate? I'm not sure I get your point.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878119923






-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871837962


   Kubernetes integration test starting
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/44984/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866818441


   **[Test build #140192 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140192/testReport)** for PR 33038 at commit [`ce48053`](https://github.com/apache/spark/commit/ce48053bc674bf7299c7c7687b7e97c0d057b9e1).
    * This patch passes all tests.
    * This patch merges cleanly.
    * This patch adds no public classes.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-872902566


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/45081/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866644116


   **[Test build #140192 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140192/testReport)** for PR 33038 at commit [`ce48053`](https://github.com/apache/spark/commit/ce48053bc674bf7299c7c7687b7e97c0d057b9e1).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-868295849


   **[Test build #140312 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140312/testReport)** for PR 33038 at commit [`cee9c3c`](https://github.com/apache/spark/commit/cee9c3cab32b14b3723f1801307c49def7949fdb).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878049079


   Kubernetes integration test status success
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/45411/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876384664


   **[Test build #140801 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140801/testReport)** for PR 33038 at commit [`4847dc2`](https://github.com/apache/spark/commit/4847dc2a5030f6356a22fba08eebdd7c32984227).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876505638


   **[Test build #140802 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140802/testReport)** for PR 33038 at commit [`556662a`](https://github.com/apache/spark/commit/556662a493f96bee3925b42c312e9d82cbd20aa6).
    * This patch **fails Spark unit tests**.
    * This patch merges cleanly.
    * This patch adds no public classes.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876563278


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/45320/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866697673


   Kubernetes integration test status failure
   URL: https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder-K8s/44719/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878075967


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/45411/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-877921683


   **[Test build #140891 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140891/testReport)** for PR 33038 at commit [`8b2f945`](https://github.com/apache/spark/commit/8b2f945537afbb6fed63c19f621b0cbe439c3a1b).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667572547



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/StateStore.scala
##########
@@ -60,21 +60,17 @@ trait ReadStateStore {
   def get(key: UnsafeRow): UnsafeRow
 
   /**
-   * Get key value pairs with optional approximate `start` and `end` extents.
-   * If the State Store implementation maintains indices for the data based on the optional
-   * `keyIndexOrdinal` over fields `keySchema` (see `StateStoreProvider.init()`), then it can use
-   * `start` and `end` to make a best-effort scan over the data. Default implementation returns
-   * the full data scan iterator, which is correct but inefficient. Custom implementations must
-   * ensure that updates (puts, removes) can be made while iterating over this iterator.
+   * Return an iterator containing all the key-value pairs which are matched with
+   * the given prefix key.
+   *
+   * Spark will provide numColsPrefixKey greater than 0 in StateStoreProvider.init method if
+   * the state store is responsible to handle the request for prefix scan. The schema of the
+   * prefix key should be same with the leftmost `numColsPrefixKey` columns of the key schema.

Review comment:
       `numColsPrefixKey <= 0` means there's no prefix key. "key with no column" doesn't make sense naturally.
   
   What about changing the sentence like below?
   
   ```
   The operator will provide numColsPrefixKey greater than 0 in StateStoreProvider.init method if the operator needs to leverage the "prefix scan" feature.
   ```
   
   I'll update the doc, and let's see whether it's good for you as well or not.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878123953






-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878123953






-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-868470455


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140312/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667611207



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/StateStore.scala
##########
@@ -60,21 +60,17 @@ trait ReadStateStore {
   def get(key: UnsafeRow): UnsafeRow
 
   /**
-   * Get key value pairs with optional approximate `start` and `end` extents.
-   * If the State Store implementation maintains indices for the data based on the optional
-   * `keyIndexOrdinal` over fields `keySchema` (see `StateStoreProvider.init()`), then it can use
-   * `start` and `end` to make a best-effort scan over the data. Default implementation returns
-   * the full data scan iterator, which is correct but inefficient. Custom implementations must
-   * ensure that updates (puts, removes) can be made while iterating over this iterator.
+   * Return an iterator containing all the key-value pairs which are matched with
+   * the given prefix key.
+   *
+   * Spark will provide numColsPrefixKey greater than 0 in StateStoreProvider.init method if
+   * the state store is responsible to handle the request for prefix scan. The schema of the
+   * prefix key should be same with the leftmost `numColsPrefixKey` columns of the key schema.
    *
-   * @param start UnsafeRow having the `keyIndexOrdinal` column set with appropriate starting value.
-   * @param end UnsafeRow having the `keyIndexOrdinal` column set with appropriate ending value.
-   * @return An iterator of key-value pairs that is guaranteed not miss any key between start and
-   *         end, both inclusive.
+   * It is expected to throw exception if Spark calls this method without setting numColsPrefixKey
+   * to the greater than 0.
    */
-  def getRange(start: Option[UnsafeRow], end: Option[UnsafeRow]): Iterator[UnsafeRowPair] = {
-    iterator()
-  }
+  def prefixScan(prefixKey: UnsafeRow): Iterator[UnsafeRowPair]

Review comment:
       I just commented on "partial implementation" of state store.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866722968


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/44719/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] viirya commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
viirya commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667439211



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/HDFSBackedStateStoreProvider.scala
##########
@@ -253,6 +239,12 @@ private[state] class HDFSBackedStateStoreProvider extends StateStoreProvider wit
     this.storeConf = storeConf
     this.hadoopConf = hadoopConf
     this.numberOfVersionsToRetainInMemory = storeConf.maxVersionsToRetainInMemory
+
+    require((keySchema.length == 0 && numColsPrefixKey == 0) ||
+      (keySchema.length > numColsPrefixKey), "The number of columns for prefix key must be " +
+      "greater than the number of columns in the key!")
+    this.numColsPrefixKey = numColsPrefixKey

Review comment:
       The number of column in the key must be greater than the number of columns for prefix key?

##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBStateEncoder.scala
##########
@@ -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.execution.streaming.state
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, JoinedRow, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider.{STATE_ENCODING_NUM_VERSION_BYTES, STATE_ENCODING_VERSION}
+import org.apache.spark.sql.types.{StructField, StructType}
+import org.apache.spark.unsafe.Platform
+
+sealed trait RocksDBStateEncoder {
+  def supportPrefixKeyScan: Boolean
+  def decodePrefixKey(groupKey: UnsafeRow): Array[Byte]
+  def extractPrefixKey(key: UnsafeRow): UnsafeRow
+
+  def encodeKey(row: UnsafeRow): Array[Byte]
+  def encodeValue(row: UnsafeRow): Array[Byte]
+
+  def decodeKey(keyBytes: Array[Byte]): UnsafeRow
+  def decodeValue(valueBytes: Array[Byte]): UnsafeRow
+  def decode(byteArrayTuple: ByteArrayPair): UnsafeRowPair
+}
+
+object RocksDBStateEncoder {
+  def getEncoder(
+      keySchema: StructType,
+      valueSchema: StructType,
+      numColsPrefixKey: Int): RocksDBStateEncoder = {
+    if (numColsPrefixKey > 0) {
+      new PrefixKeyScanStateEncoder(keySchema, valueSchema, numColsPrefixKey)
+    } else {
+      new NoPrefixKeyStateEncoder(keySchema, valueSchema)
+    }
+  }
+
+  /**
+   * Encode the UnsafeRow of N bytes as a N+1 byte array.
+   * @note This creates a new byte array and memcopies the UnsafeRow to the new array.
+   */
+  def encodeUnsafeRow(row: UnsafeRow): Array[Byte] = {
+    val bytesToEncode = row.getBytes
+    val encodedBytes = new Array[Byte](bytesToEncode.length + STATE_ENCODING_NUM_VERSION_BYTES)
+    Platform.putByte(encodedBytes, Platform.BYTE_ARRAY_OFFSET, STATE_ENCODING_VERSION)
+    // Platform.BYTE_ARRAY_OFFSET is the recommended way to memcopy b/w byte arrays. See Platform.
+    Platform.copyMemory(
+      bytesToEncode, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+      bytesToEncode.length)
+    encodedBytes
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], numFields: Int): UnsafeRow = {
+    if (bytes != null) {
+      val row = new UnsafeRow(numFields)
+      decodeToUnsafeRow(bytes, row)
+    } else {
+      null
+    }
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], reusedRow: UnsafeRow): UnsafeRow = {
+    if (bytes != null) {
+      // Platform.BYTE_ARRAY_OFFSET is the recommended way refer to the 1st offset. See Platform.
+      reusedRow.pointTo(
+        bytes,
+        Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+        bytes.length - STATE_ENCODING_NUM_VERSION_BYTES)
+      reusedRow
+    } else {
+      null
+    }
+  }
+}
+
+class PrefixKeyScanStateEncoder(
+    keySchema: StructType,
+    valueSchema: StructType,
+    numColsPrefixKey: Int) extends RocksDBStateEncoder {
+
+  import RocksDBStateEncoder._
+
+  require(keySchema.length > numColsPrefixKey, "The number of columns for prefix key must be " +
+    "greater than the number of columns in the key!")
+
+  private val groupKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.take(numColsPrefixKey)
+  }
+
+  private val remainingKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.drop(numColsPrefixKey)
+  }
+
+  private val prefixKeyProjection: UnsafeProjection = {
+    val refs = groupKeyFieldsWithIdx.map(x => BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  private val remainingKeyProjection: UnsafeProjection = {
+    val refs = remainingKeyFieldsWithIdx.map(x =>
+      BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  // This is quite simple to do - just bind sequentially, as we don't change the order.
+  private val restoreKeyProjection: UnsafeProjection = UnsafeProjection.create(keySchema)
+
+  // Reusable objects
+  private val joinedRowOnKey = new JoinedRow()
+  private val valueRow = new UnsafeRow(valueSchema.size)
+  private val rowTuple = new UnsafeRowPair()
+
+  override def encodeKey(row: UnsafeRow): Array[Byte] = {
+    val prefixKeyEncoded = encodeUnsafeRow(extractPrefixKey(row))
+    val remainingEncoded = encodeUnsafeRow(remainingKeyProjection(row))
+
+    val encodedBytes = new Array[Byte](prefixKeyEncoded.length + remainingEncoded.length + 4)
+    Platform.putInt(encodedBytes, Platform.BYTE_ARRAY_OFFSET, prefixKeyEncoded.length)
+    Platform.copyMemory(prefixKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4, prefixKeyEncoded.length)
+    // NOTE: We don't put the length of remainingEncoded as we can calculate later
+    // on deserialization.
+    Platform.copyMemory(remainingEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4 + prefixKeyEncoded.length,
+      remainingEncoded.length)
+
+    encodedBytes
+  }
+
+  override def encodeValue(row: UnsafeRow): Array[Byte] = encodeUnsafeRow(row)
+
+  override def decodeKey(keyBytes: Array[Byte]): UnsafeRow = {
+    val groupKeyEncodedLen = Platform.getInt(keyBytes, Platform.BYTE_ARRAY_OFFSET)
+    val groupKeyEncoded = new Array[Byte](groupKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4, groupKeyEncoded,
+      Platform.BYTE_ARRAY_OFFSET, groupKeyEncodedLen)
+
+    // Here we calculate the remainingKeyEncodedLen leveraging the length of keyBytes
+    val remainingKeyEncodedLen = keyBytes.length - 4 - groupKeyEncodedLen
+
+    val remainingKeyEncoded = new Array[Byte](remainingKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4 +
+      groupKeyEncodedLen, remainingKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      remainingKeyEncodedLen)
+
+    val groupKeyDecoded = decodeToUnsafeRow(groupKeyEncoded, groupKeyFieldsWithIdx.length)
+    val remainingKeyDecoded = decodeToUnsafeRow(remainingKeyEncoded, numFields = 1)
+
+    restoreKeyProjection(joinedRowOnKey.withLeft(groupKeyDecoded).withRight(remainingKeyDecoded))
+  }
+
+  override def decodeValue(valueBytes: Array[Byte]): UnsafeRow = {
+    decodeToUnsafeRow(valueBytes, valueRow)
+  }
+
+  override def extractPrefixKey(key: UnsafeRow): UnsafeRow = {
+    prefixKeyProjection(key)
+  }
+
+  override def decodePrefixKey(groupKey: UnsafeRow): Array[Byte] = {

Review comment:
       What this method does more like `encodePrefixKey`?

##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDB.scala
##########
@@ -185,6 +189,33 @@ class RocksDB(
     }
   }
 
+  def prefixScan(prefix: Array[Byte]): Iterator[ByteArrayPair] = {
+    val threadId = Thread.currentThread().getId
+    val iter = prefixScanReuseIter.computeIfAbsent(threadId, tid => {
+      val it = writeBatch.newIteratorWithBase(db.newIterator())
+      logInfo(s"Getting iterator from version $loadedVersion for prefix scan on " +
+        s"tid $tid")

Review comment:
       tid -> thread id?

##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBStateEncoder.scala
##########
@@ -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.execution.streaming.state
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, JoinedRow, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider.{STATE_ENCODING_NUM_VERSION_BYTES, STATE_ENCODING_VERSION}
+import org.apache.spark.sql.types.{StructField, StructType}
+import org.apache.spark.unsafe.Platform
+
+sealed trait RocksDBStateEncoder {
+  def supportPrefixKeyScan: Boolean
+  def decodePrefixKey(groupKey: UnsafeRow): Array[Byte]
+  def extractPrefixKey(key: UnsafeRow): UnsafeRow
+
+  def encodeKey(row: UnsafeRow): Array[Byte]
+  def encodeValue(row: UnsafeRow): Array[Byte]
+
+  def decodeKey(keyBytes: Array[Byte]): UnsafeRow
+  def decodeValue(valueBytes: Array[Byte]): UnsafeRow
+  def decode(byteArrayTuple: ByteArrayPair): UnsafeRowPair
+}
+
+object RocksDBStateEncoder {
+  def getEncoder(
+      keySchema: StructType,
+      valueSchema: StructType,
+      numColsPrefixKey: Int): RocksDBStateEncoder = {
+    if (numColsPrefixKey > 0) {
+      new PrefixKeyScanStateEncoder(keySchema, valueSchema, numColsPrefixKey)
+    } else {
+      new NoPrefixKeyStateEncoder(keySchema, valueSchema)
+    }
+  }
+
+  /**
+   * Encode the UnsafeRow of N bytes as a N+1 byte array.
+   * @note This creates a new byte array and memcopies the UnsafeRow to the new array.
+   */
+  def encodeUnsafeRow(row: UnsafeRow): Array[Byte] = {
+    val bytesToEncode = row.getBytes
+    val encodedBytes = new Array[Byte](bytesToEncode.length + STATE_ENCODING_NUM_VERSION_BYTES)
+    Platform.putByte(encodedBytes, Platform.BYTE_ARRAY_OFFSET, STATE_ENCODING_VERSION)
+    // Platform.BYTE_ARRAY_OFFSET is the recommended way to memcopy b/w byte arrays. See Platform.
+    Platform.copyMemory(
+      bytesToEncode, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+      bytesToEncode.length)
+    encodedBytes
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], numFields: Int): UnsafeRow = {
+    if (bytes != null) {
+      val row = new UnsafeRow(numFields)
+      decodeToUnsafeRow(bytes, row)
+    } else {
+      null
+    }
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], reusedRow: UnsafeRow): UnsafeRow = {
+    if (bytes != null) {
+      // Platform.BYTE_ARRAY_OFFSET is the recommended way refer to the 1st offset. See Platform.
+      reusedRow.pointTo(
+        bytes,
+        Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+        bytes.length - STATE_ENCODING_NUM_VERSION_BYTES)
+      reusedRow
+    } else {
+      null
+    }
+  }
+}
+
+class PrefixKeyScanStateEncoder(
+    keySchema: StructType,
+    valueSchema: StructType,
+    numColsPrefixKey: Int) extends RocksDBStateEncoder {
+
+  import RocksDBStateEncoder._
+
+  require(keySchema.length > numColsPrefixKey, "The number of columns for prefix key must be " +
+    "greater than the number of columns in the key!")
+

Review comment:
       The number of columns in the key must be greater than the number of columns for prefix key?

##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBStateEncoder.scala
##########
@@ -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.execution.streaming.state
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, JoinedRow, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider.{STATE_ENCODING_NUM_VERSION_BYTES, STATE_ENCODING_VERSION}
+import org.apache.spark.sql.types.{StructField, StructType}
+import org.apache.spark.unsafe.Platform
+
+sealed trait RocksDBStateEncoder {
+  def supportPrefixKeyScan: Boolean
+  def decodePrefixKey(groupKey: UnsafeRow): Array[Byte]
+  def extractPrefixKey(key: UnsafeRow): UnsafeRow
+
+  def encodeKey(row: UnsafeRow): Array[Byte]
+  def encodeValue(row: UnsafeRow): Array[Byte]
+
+  def decodeKey(keyBytes: Array[Byte]): UnsafeRow
+  def decodeValue(valueBytes: Array[Byte]): UnsafeRow
+  def decode(byteArrayTuple: ByteArrayPair): UnsafeRowPair
+}
+
+object RocksDBStateEncoder {
+  def getEncoder(
+      keySchema: StructType,
+      valueSchema: StructType,
+      numColsPrefixKey: Int): RocksDBStateEncoder = {
+    if (numColsPrefixKey > 0) {
+      new PrefixKeyScanStateEncoder(keySchema, valueSchema, numColsPrefixKey)
+    } else {
+      new NoPrefixKeyStateEncoder(keySchema, valueSchema)
+    }
+  }
+
+  /**
+   * Encode the UnsafeRow of N bytes as a N+1 byte array.
+   * @note This creates a new byte array and memcopies the UnsafeRow to the new array.
+   */
+  def encodeUnsafeRow(row: UnsafeRow): Array[Byte] = {
+    val bytesToEncode = row.getBytes
+    val encodedBytes = new Array[Byte](bytesToEncode.length + STATE_ENCODING_NUM_VERSION_BYTES)
+    Platform.putByte(encodedBytes, Platform.BYTE_ARRAY_OFFSET, STATE_ENCODING_VERSION)
+    // Platform.BYTE_ARRAY_OFFSET is the recommended way to memcopy b/w byte arrays. See Platform.
+    Platform.copyMemory(
+      bytesToEncode, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+      bytesToEncode.length)
+    encodedBytes
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], numFields: Int): UnsafeRow = {
+    if (bytes != null) {
+      val row = new UnsafeRow(numFields)
+      decodeToUnsafeRow(bytes, row)
+    } else {
+      null
+    }
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], reusedRow: UnsafeRow): UnsafeRow = {
+    if (bytes != null) {
+      // Platform.BYTE_ARRAY_OFFSET is the recommended way refer to the 1st offset. See Platform.
+      reusedRow.pointTo(
+        bytes,
+        Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+        bytes.length - STATE_ENCODING_NUM_VERSION_BYTES)
+      reusedRow
+    } else {
+      null
+    }
+  }
+}
+
+class PrefixKeyScanStateEncoder(
+    keySchema: StructType,
+    valueSchema: StructType,
+    numColsPrefixKey: Int) extends RocksDBStateEncoder {
+
+  import RocksDBStateEncoder._
+
+  require(keySchema.length > numColsPrefixKey, "The number of columns for prefix key must be " +
+    "greater than the number of columns in the key!")
+
+  private val groupKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.take(numColsPrefixKey)
+  }
+
+  private val remainingKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.drop(numColsPrefixKey)
+  }
+
+  private val prefixKeyProjection: UnsafeProjection = {
+    val refs = groupKeyFieldsWithIdx.map(x => BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  private val remainingKeyProjection: UnsafeProjection = {
+    val refs = remainingKeyFieldsWithIdx.map(x =>
+      BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  // This is quite simple to do - just bind sequentially, as we don't change the order.
+  private val restoreKeyProjection: UnsafeProjection = UnsafeProjection.create(keySchema)
+
+  // Reusable objects
+  private val joinedRowOnKey = new JoinedRow()
+  private val valueRow = new UnsafeRow(valueSchema.size)
+  private val rowTuple = new UnsafeRowPair()
+
+  override def encodeKey(row: UnsafeRow): Array[Byte] = {
+    val prefixKeyEncoded = encodeUnsafeRow(extractPrefixKey(row))
+    val remainingEncoded = encodeUnsafeRow(remainingKeyProjection(row))
+
+    val encodedBytes = new Array[Byte](prefixKeyEncoded.length + remainingEncoded.length + 4)
+    Platform.putInt(encodedBytes, Platform.BYTE_ARRAY_OFFSET, prefixKeyEncoded.length)
+    Platform.copyMemory(prefixKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4, prefixKeyEncoded.length)
+    // NOTE: We don't put the length of remainingEncoded as we can calculate later
+    // on deserialization.
+    Platform.copyMemory(remainingEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4 + prefixKeyEncoded.length,
+      remainingEncoded.length)
+
+    encodedBytes
+  }
+
+  override def encodeValue(row: UnsafeRow): Array[Byte] = encodeUnsafeRow(row)
+
+  override def decodeKey(keyBytes: Array[Byte]): UnsafeRow = {
+    val groupKeyEncodedLen = Platform.getInt(keyBytes, Platform.BYTE_ARRAY_OFFSET)
+    val groupKeyEncoded = new Array[Byte](groupKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4, groupKeyEncoded,
+      Platform.BYTE_ARRAY_OFFSET, groupKeyEncodedLen)
+
+    // Here we calculate the remainingKeyEncodedLen leveraging the length of keyBytes
+    val remainingKeyEncodedLen = keyBytes.length - 4 - groupKeyEncodedLen
+
+    val remainingKeyEncoded = new Array[Byte](remainingKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4 +
+      groupKeyEncodedLen, remainingKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      remainingKeyEncodedLen)
+
+    val groupKeyDecoded = decodeToUnsafeRow(groupKeyEncoded, groupKeyFieldsWithIdx.length)
+    val remainingKeyDecoded = decodeToUnsafeRow(remainingKeyEncoded, numFields = 1)
+
+    restoreKeyProjection(joinedRowOnKey.withLeft(groupKeyDecoded).withRight(remainingKeyDecoded))
+  }
+
+  override def decodeValue(valueBytes: Array[Byte]): UnsafeRow = {
+    decodeToUnsafeRow(valueBytes, valueRow)
+  }
+
+  override def extractPrefixKey(key: UnsafeRow): UnsafeRow = {
+    prefixKeyProjection(key)
+  }
+
+  override def decodePrefixKey(groupKey: UnsafeRow): Array[Byte] = {
+    val groupKeyEncoded = encodeUnsafeRow(groupKey)

Review comment:
       Shall we name `prefixKeyEncoded` (and other similar variables) to be consistent with method/API name?

##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/StateStore.scala
##########
@@ -60,21 +60,17 @@ trait ReadStateStore {
   def get(key: UnsafeRow): UnsafeRow
 
   /**
-   * Get key value pairs with optional approximate `start` and `end` extents.
-   * If the State Store implementation maintains indices for the data based on the optional
-   * `keyIndexOrdinal` over fields `keySchema` (see `StateStoreProvider.init()`), then it can use
-   * `start` and `end` to make a best-effort scan over the data. Default implementation returns
-   * the full data scan iterator, which is correct but inefficient. Custom implementations must
-   * ensure that updates (puts, removes) can be made while iterating over this iterator.
+   * Return an iterator containing all the key-value pairs which are matched with
+   * the given prefix key.
+   *
+   * Spark will provide numColsPrefixKey greater than 0 in StateStoreProvider.init method if
+   * the state store is responsible to handle the request for prefix scan. The schema of the
+   * prefix key should be same with the leftmost `numColsPrefixKey` columns of the key schema.
    *
-   * @param start UnsafeRow having the `keyIndexOrdinal` column set with appropriate starting value.
-   * @param end UnsafeRow having the `keyIndexOrdinal` column set with appropriate ending value.
-   * @return An iterator of key-value pairs that is guaranteed not miss any key between start and
-   *         end, both inclusive.
+   * It is expected to throw exception if Spark calls this method without setting numColsPrefixKey
+   * to the greater than 0.
    */
-  def getRange(start: Option[UnsafeRow], end: Option[UnsafeRow]): Iterator[UnsafeRowPair] = {
-    iterator()
-  }
+  def prefixScan(prefixKey: UnsafeRow): Iterator[UnsafeRowPair]

Review comment:
       E.g., `MemoryStateStore` doesn't support it.

##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBStateEncoder.scala
##########
@@ -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.execution.streaming.state
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, JoinedRow, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider.{STATE_ENCODING_NUM_VERSION_BYTES, STATE_ENCODING_VERSION}
+import org.apache.spark.sql.types.{StructField, StructType}
+import org.apache.spark.unsafe.Platform
+
+sealed trait RocksDBStateEncoder {
+  def supportPrefixKeyScan: Boolean
+  def decodePrefixKey(groupKey: UnsafeRow): Array[Byte]
+  def extractPrefixKey(key: UnsafeRow): UnsafeRow
+
+  def encodeKey(row: UnsafeRow): Array[Byte]
+  def encodeValue(row: UnsafeRow): Array[Byte]
+
+  def decodeKey(keyBytes: Array[Byte]): UnsafeRow
+  def decodeValue(valueBytes: Array[Byte]): UnsafeRow
+  def decode(byteArrayTuple: ByteArrayPair): UnsafeRowPair
+}
+
+object RocksDBStateEncoder {
+  def getEncoder(
+      keySchema: StructType,
+      valueSchema: StructType,
+      numColsPrefixKey: Int): RocksDBStateEncoder = {
+    if (numColsPrefixKey > 0) {
+      new PrefixKeyScanStateEncoder(keySchema, valueSchema, numColsPrefixKey)
+    } else {
+      new NoPrefixKeyStateEncoder(keySchema, valueSchema)
+    }
+  }
+
+  /**
+   * Encode the UnsafeRow of N bytes as a N+1 byte array.
+   * @note This creates a new byte array and memcopies the UnsafeRow to the new array.
+   */
+  def encodeUnsafeRow(row: UnsafeRow): Array[Byte] = {
+    val bytesToEncode = row.getBytes
+    val encodedBytes = new Array[Byte](bytesToEncode.length + STATE_ENCODING_NUM_VERSION_BYTES)
+    Platform.putByte(encodedBytes, Platform.BYTE_ARRAY_OFFSET, STATE_ENCODING_VERSION)
+    // Platform.BYTE_ARRAY_OFFSET is the recommended way to memcopy b/w byte arrays. See Platform.
+    Platform.copyMemory(
+      bytesToEncode, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+      bytesToEncode.length)
+    encodedBytes
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], numFields: Int): UnsafeRow = {
+    if (bytes != null) {
+      val row = new UnsafeRow(numFields)
+      decodeToUnsafeRow(bytes, row)
+    } else {
+      null
+    }
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], reusedRow: UnsafeRow): UnsafeRow = {
+    if (bytes != null) {
+      // Platform.BYTE_ARRAY_OFFSET is the recommended way refer to the 1st offset. See Platform.
+      reusedRow.pointTo(
+        bytes,
+        Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+        bytes.length - STATE_ENCODING_NUM_VERSION_BYTES)
+      reusedRow
+    } else {
+      null
+    }
+  }
+}
+
+class PrefixKeyScanStateEncoder(
+    keySchema: StructType,
+    valueSchema: StructType,
+    numColsPrefixKey: Int) extends RocksDBStateEncoder {
+
+  import RocksDBStateEncoder._
+
+  require(keySchema.length > numColsPrefixKey, "The number of columns for prefix key must be " +
+    "greater than the number of columns in the key!")
+
+  private val groupKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.take(numColsPrefixKey)
+  }
+
+  private val remainingKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.drop(numColsPrefixKey)
+  }
+
+  private val prefixKeyProjection: UnsafeProjection = {
+    val refs = groupKeyFieldsWithIdx.map(x => BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  private val remainingKeyProjection: UnsafeProjection = {
+    val refs = remainingKeyFieldsWithIdx.map(x =>
+      BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  // This is quite simple to do - just bind sequentially, as we don't change the order.
+  private val restoreKeyProjection: UnsafeProjection = UnsafeProjection.create(keySchema)
+
+  // Reusable objects
+  private val joinedRowOnKey = new JoinedRow()
+  private val valueRow = new UnsafeRow(valueSchema.size)
+  private val rowTuple = new UnsafeRowPair()
+
+  override def encodeKey(row: UnsafeRow): Array[Byte] = {
+    val prefixKeyEncoded = encodeUnsafeRow(extractPrefixKey(row))
+    val remainingEncoded = encodeUnsafeRow(remainingKeyProjection(row))
+
+    val encodedBytes = new Array[Byte](prefixKeyEncoded.length + remainingEncoded.length + 4)
+    Platform.putInt(encodedBytes, Platform.BYTE_ARRAY_OFFSET, prefixKeyEncoded.length)
+    Platform.copyMemory(prefixKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4, prefixKeyEncoded.length)
+    // NOTE: We don't put the length of remainingEncoded as we can calculate later
+    // on deserialization.
+    Platform.copyMemory(remainingEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4 + prefixKeyEncoded.length,
+      remainingEncoded.length)
+
+    encodedBytes
+  }
+
+  override def encodeValue(row: UnsafeRow): Array[Byte] = encodeUnsafeRow(row)
+
+  override def decodeKey(keyBytes: Array[Byte]): UnsafeRow = {
+    val groupKeyEncodedLen = Platform.getInt(keyBytes, Platform.BYTE_ARRAY_OFFSET)
+    val groupKeyEncoded = new Array[Byte](groupKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4, groupKeyEncoded,
+      Platform.BYTE_ARRAY_OFFSET, groupKeyEncodedLen)
+
+    // Here we calculate the remainingKeyEncodedLen leveraging the length of keyBytes
+    val remainingKeyEncodedLen = keyBytes.length - 4 - groupKeyEncodedLen
+
+    val remainingKeyEncoded = new Array[Byte](remainingKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4 +
+      groupKeyEncodedLen, remainingKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      remainingKeyEncodedLen)
+
+    val groupKeyDecoded = decodeToUnsafeRow(groupKeyEncoded, groupKeyFieldsWithIdx.length)
+    val remainingKeyDecoded = decodeToUnsafeRow(remainingKeyEncoded, numFields = 1)

Review comment:
       why `numFields` is always 1 here?

##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBStateStoreProvider.scala
##########
@@ -147,14 +146,21 @@ private[state] class RocksDBStateStoreProvider
       stateStoreId: StateStoreId,
       keySchema: StructType,
       valueSchema: StructType,
-      indexOrdinal: Option[Int],
+      numColsPrefixKey: Int,
       storeConf: StateStoreConf,
       hadoopConf: Configuration): Unit = {
     this.stateStoreId_ = stateStoreId
     this.keySchema = keySchema
     this.valueSchema = valueSchema
     this.storeConf = storeConf
     this.hadoopConf = hadoopConf
+
+    require((keySchema.length == 0 && numColsPrefixKey == 0) ||
+      (keySchema.length > numColsPrefixKey), "The number of columns for prefix key must be " +
+      "greater than the number of columns in the key!")

Review comment:
       The number of columns in the key must be greater than the number of columns for prefix key?

##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/StateStore.scala
##########
@@ -60,21 +60,17 @@ trait ReadStateStore {
   def get(key: UnsafeRow): UnsafeRow
 
   /**
-   * Get key value pairs with optional approximate `start` and `end` extents.
-   * If the State Store implementation maintains indices for the data based on the optional
-   * `keyIndexOrdinal` over fields `keySchema` (see `StateStoreProvider.init()`), then it can use
-   * `start` and `end` to make a best-effort scan over the data. Default implementation returns
-   * the full data scan iterator, which is correct but inefficient. Custom implementations must
-   * ensure that updates (puts, removes) can be made while iterating over this iterator.
+   * Return an iterator containing all the key-value pairs which are matched with
+   * the given prefix key.
+   *
+   * Spark will provide numColsPrefixKey greater than 0 in StateStoreProvider.init method if
+   * the state store is responsible to handle the request for prefix scan. The schema of the
+   * prefix key should be same with the leftmost `numColsPrefixKey` columns of the key schema.
    *
-   * @param start UnsafeRow having the `keyIndexOrdinal` column set with appropriate starting value.
-   * @param end UnsafeRow having the `keyIndexOrdinal` column set with appropriate ending value.
-   * @return An iterator of key-value pairs that is guaranteed not miss any key between start and
-   *         end, both inclusive.
+   * It is expected to throw exception if Spark calls this method without setting numColsPrefixKey
+   * to the greater than 0.
    */
-  def getRange(start: Option[UnsafeRow], end: Option[UnsafeRow]): Iterator[UnsafeRowPair] = {
-    iterator()
-  }
+  def prefixScan(prefixKey: UnsafeRow): Iterator[UnsafeRowPair]

Review comment:
       Is this necessary to support by third-party StateStore implementation? If an implementation doesn't support it, what would happens? Could you clarify it in the doc?

##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/StateStore.scala
##########
@@ -251,16 +250,15 @@ trait StateStoreProvider {
    * @param stateStoreId Id of the versioned StateStores that this provider will generate
    * @param keySchema Schema of keys to be stored
    * @param valueSchema Schema of value to be stored
-   * @param keyIndexOrdinal Optional column (represent as the ordinal of the field in keySchema) by
-   *                        which the StateStore implementation could index the data.
+   * @param numColsPrefixKey The number of leftmost columns to be used as prefix key.

Review comment:
       "A value not greater than 0 means that the StateStore doesn't support `prefixScan` API."




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-871821101


   **[Test build #140470 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140470/testReport)** for PR 33038 at commit [`36cdeab`](https://github.com/apache/spark/commit/36cdeab1483d3ac4d1e015f3ebf8d80f2148bb8a).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-877958525


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder-K8s/45402/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866629394


   We applied the proposal into native session window implementation internally, and ran some benchmarks. This proposal shows similar performance compared with the approach we took in #31937 on HDFS backed state store provider, and even quite higher on RocksDB state store provider.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866644116


   **[Test build #140192 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140192/testReport)** for PR 33038 at commit [`ce48053`](https://github.com/apache/spark/commit/ce48053bc674bf7299c7c7687b7e97c0d057b9e1).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878119923






-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876602677


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140809/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] viirya commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
viirya commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-872003647


   @HeartSaVioR thanks for ping. I will look into this in next days.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] AmplabJenkins commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
AmplabJenkins commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-878005490


   
   Refer to this link for build results (access rights to CI server needed): 
   https://amplab.cs.berkeley.edu/jenkins//job/SparkPullRequestBuilder/140891/
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876904325


   **[Test build #140826 has finished](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140826/testReport)** for PR 33038 at commit [`a0f34b7`](https://github.com/apache/spark/commit/a0f34b77b25e32bd5002f9df5e80cdc22089a84c).
    * This patch passes all tests.
    * This patch merges cleanly.
    * This patch adds no public classes.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667571191



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/HDFSBackedStateStoreProvider.scala
##########
@@ -253,6 +239,12 @@ private[state] class HDFSBackedStateStoreProvider extends StateStoreProvider wit
     this.storeConf = storeConf
     this.hadoopConf = hadoopConf
     this.numberOfVersionsToRetainInMemory = storeConf.maxVersionsToRetainInMemory
+
+    require((keySchema.length == 0 && numColsPrefixKey == 0) ||
+      (keySchema.length > numColsPrefixKey), "The number of columns for prefix key must be " +
+      "greater than the number of columns in the key!")
+    this.numColsPrefixKey = numColsPrefixKey

Review comment:
       Nice finding!




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] viirya commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
viirya commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667442678



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/StateStore.scala
##########
@@ -60,21 +60,17 @@ trait ReadStateStore {
   def get(key: UnsafeRow): UnsafeRow
 
   /**
-   * Get key value pairs with optional approximate `start` and `end` extents.
-   * If the State Store implementation maintains indices for the data based on the optional
-   * `keyIndexOrdinal` over fields `keySchema` (see `StateStoreProvider.init()`), then it can use
-   * `start` and `end` to make a best-effort scan over the data. Default implementation returns
-   * the full data scan iterator, which is correct but inefficient. Custom implementations must
-   * ensure that updates (puts, removes) can be made while iterating over this iterator.
+   * Return an iterator containing all the key-value pairs which are matched with
+   * the given prefix key.
+   *
+   * Spark will provide numColsPrefixKey greater than 0 in StateStoreProvider.init method if
+   * the state store is responsible to handle the request for prefix scan. The schema of the
+   * prefix key should be same with the leftmost `numColsPrefixKey` columns of the key schema.

Review comment:
       "...if the state store is responsible to handle the request for prefix scan." This reads a bit confusing.
   
   It sounds like, except for state store, there is another class can be responsible to handle the request for prefix scan. And if Spark provides `numColsPrefixKey > 0`, it will ask the state store to handle. If `numColsPrefixKey <= 0`, it will ask the other one to handle.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on a change in pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on a change in pull request #33038:
URL: https://github.com/apache/spark/pull/33038#discussion_r667571374



##########
File path: sql/core/src/main/scala/org/apache/spark/sql/execution/streaming/state/RocksDBStateEncoder.scala
##########
@@ -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.execution.streaming.state
+
+import org.apache.spark.sql.catalyst.expressions.{BoundReference, JoinedRow, UnsafeProjection, UnsafeRow}
+import org.apache.spark.sql.execution.streaming.state.RocksDBStateStoreProvider.{STATE_ENCODING_NUM_VERSION_BYTES, STATE_ENCODING_VERSION}
+import org.apache.spark.sql.types.{StructField, StructType}
+import org.apache.spark.unsafe.Platform
+
+sealed trait RocksDBStateEncoder {
+  def supportPrefixKeyScan: Boolean
+  def decodePrefixKey(groupKey: UnsafeRow): Array[Byte]
+  def extractPrefixKey(key: UnsafeRow): UnsafeRow
+
+  def encodeKey(row: UnsafeRow): Array[Byte]
+  def encodeValue(row: UnsafeRow): Array[Byte]
+
+  def decodeKey(keyBytes: Array[Byte]): UnsafeRow
+  def decodeValue(valueBytes: Array[Byte]): UnsafeRow
+  def decode(byteArrayTuple: ByteArrayPair): UnsafeRowPair
+}
+
+object RocksDBStateEncoder {
+  def getEncoder(
+      keySchema: StructType,
+      valueSchema: StructType,
+      numColsPrefixKey: Int): RocksDBStateEncoder = {
+    if (numColsPrefixKey > 0) {
+      new PrefixKeyScanStateEncoder(keySchema, valueSchema, numColsPrefixKey)
+    } else {
+      new NoPrefixKeyStateEncoder(keySchema, valueSchema)
+    }
+  }
+
+  /**
+   * Encode the UnsafeRow of N bytes as a N+1 byte array.
+   * @note This creates a new byte array and memcopies the UnsafeRow to the new array.
+   */
+  def encodeUnsafeRow(row: UnsafeRow): Array[Byte] = {
+    val bytesToEncode = row.getBytes
+    val encodedBytes = new Array[Byte](bytesToEncode.length + STATE_ENCODING_NUM_VERSION_BYTES)
+    Platform.putByte(encodedBytes, Platform.BYTE_ARRAY_OFFSET, STATE_ENCODING_VERSION)
+    // Platform.BYTE_ARRAY_OFFSET is the recommended way to memcopy b/w byte arrays. See Platform.
+    Platform.copyMemory(
+      bytesToEncode, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+      bytesToEncode.length)
+    encodedBytes
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], numFields: Int): UnsafeRow = {
+    if (bytes != null) {
+      val row = new UnsafeRow(numFields)
+      decodeToUnsafeRow(bytes, row)
+    } else {
+      null
+    }
+  }
+
+  def decodeToUnsafeRow(bytes: Array[Byte], reusedRow: UnsafeRow): UnsafeRow = {
+    if (bytes != null) {
+      // Platform.BYTE_ARRAY_OFFSET is the recommended way refer to the 1st offset. See Platform.
+      reusedRow.pointTo(
+        bytes,
+        Platform.BYTE_ARRAY_OFFSET + STATE_ENCODING_NUM_VERSION_BYTES,
+        bytes.length - STATE_ENCODING_NUM_VERSION_BYTES)
+      reusedRow
+    } else {
+      null
+    }
+  }
+}
+
+class PrefixKeyScanStateEncoder(
+    keySchema: StructType,
+    valueSchema: StructType,
+    numColsPrefixKey: Int) extends RocksDBStateEncoder {
+
+  import RocksDBStateEncoder._
+
+  require(keySchema.length > numColsPrefixKey, "The number of columns for prefix key must be " +
+    "greater than the number of columns in the key!")
+
+  private val groupKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.take(numColsPrefixKey)
+  }
+
+  private val remainingKeyFieldsWithIdx: Seq[(StructField, Int)] = {
+    keySchema.zipWithIndex.drop(numColsPrefixKey)
+  }
+
+  private val prefixKeyProjection: UnsafeProjection = {
+    val refs = groupKeyFieldsWithIdx.map(x => BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  private val remainingKeyProjection: UnsafeProjection = {
+    val refs = remainingKeyFieldsWithIdx.map(x =>
+      BoundReference(x._2, x._1.dataType, x._1.nullable))
+    UnsafeProjection.create(refs)
+  }
+
+  // This is quite simple to do - just bind sequentially, as we don't change the order.
+  private val restoreKeyProjection: UnsafeProjection = UnsafeProjection.create(keySchema)
+
+  // Reusable objects
+  private val joinedRowOnKey = new JoinedRow()
+  private val valueRow = new UnsafeRow(valueSchema.size)
+  private val rowTuple = new UnsafeRowPair()
+
+  override def encodeKey(row: UnsafeRow): Array[Byte] = {
+    val prefixKeyEncoded = encodeUnsafeRow(extractPrefixKey(row))
+    val remainingEncoded = encodeUnsafeRow(remainingKeyProjection(row))
+
+    val encodedBytes = new Array[Byte](prefixKeyEncoded.length + remainingEncoded.length + 4)
+    Platform.putInt(encodedBytes, Platform.BYTE_ARRAY_OFFSET, prefixKeyEncoded.length)
+    Platform.copyMemory(prefixKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4, prefixKeyEncoded.length)
+    // NOTE: We don't put the length of remainingEncoded as we can calculate later
+    // on deserialization.
+    Platform.copyMemory(remainingEncoded, Platform.BYTE_ARRAY_OFFSET,
+      encodedBytes, Platform.BYTE_ARRAY_OFFSET + 4 + prefixKeyEncoded.length,
+      remainingEncoded.length)
+
+    encodedBytes
+  }
+
+  override def encodeValue(row: UnsafeRow): Array[Byte] = encodeUnsafeRow(row)
+
+  override def decodeKey(keyBytes: Array[Byte]): UnsafeRow = {
+    val groupKeyEncodedLen = Platform.getInt(keyBytes, Platform.BYTE_ARRAY_OFFSET)
+    val groupKeyEncoded = new Array[Byte](groupKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4, groupKeyEncoded,
+      Platform.BYTE_ARRAY_OFFSET, groupKeyEncodedLen)
+
+    // Here we calculate the remainingKeyEncodedLen leveraging the length of keyBytes
+    val remainingKeyEncodedLen = keyBytes.length - 4 - groupKeyEncodedLen
+
+    val remainingKeyEncoded = new Array[Byte](remainingKeyEncodedLen)
+    Platform.copyMemory(keyBytes, Platform.BYTE_ARRAY_OFFSET + 4 +
+      groupKeyEncodedLen, remainingKeyEncoded, Platform.BYTE_ARRAY_OFFSET,
+      remainingKeyEncodedLen)
+
+    val groupKeyDecoded = decodeToUnsafeRow(groupKeyEncoded, groupKeyFieldsWithIdx.length)
+    val remainingKeyDecoded = decodeToUnsafeRow(remainingKeyEncoded, numFields = 1)

Review comment:
       My bad. Nice finding!




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] SparkQA removed a comment on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
SparkQA removed a comment on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-876820847


   **[Test build #140826 has started](https://amplab.cs.berkeley.edu/jenkins/job/SparkPullRequestBuilder/140826/testReport)** for PR 33038 at commit [`a0f34b7`](https://github.com/apache/spark/commit/a0f34b77b25e32bd5002f9df5e80cdc22089a84c).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@spark.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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


[GitHub] [spark] HeartSaVioR commented on pull request #33038: [SPARK-35861][SS] Introduce "prefix match scan" feature on state store

Posted by GitBox <gi...@apache.org>.
HeartSaVioR commented on pull request #33038:
URL: https://github.com/apache/spark/pull/33038#issuecomment-866627109


   Please note that the huge line of changes in test suite are due to change the schema of the key from single column to multiple columns. The single column of key schema can't test prefix scan, and there're lots of helper methods tailored to the existing schema.
   
   So either I have to duplicate them to have individual test suite for prefix scan, or I have to change the existing schema to have multiple columns on the key. I took latter as the final form of the codebase would be better than duplicating them.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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