From 55e3bb3b9202bcec83dec59d6a08ff4a793f99c8 Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <vdavydov@tarantool.org>
Date: Tue, 25 Oct 2022 15:27:17 +0300
Subject: [PATCH] memtx: add option to disable decompression of read view
 tuples

We need this option to implement a basic MT-safe read view C API
in the EE repository.

Closes #7815

NO_DOC=internal
NO_CHANGELOG=internal
NO_TEST=will be added to the EE repository
---
 src/box/index.h         | 18 ++++++++++++------
 src/box/memtx_engine.cc |  9 +++++++--
 src/box/memtx_engine.h  | 16 +++++++++++-----
 src/box/memtx_hash.cc   |  5 ++++-
 src/box/memtx_tree.cc   |  5 ++++-
 src/box/read_view.c     |  1 +
 src/box/read_view.h     |  9 +++++++++
 7 files changed, 48 insertions(+), 15 deletions(-)

diff --git a/src/box/index.h b/src/box/index.h
index dc5f4084d9..32545cdcf3 100644
--- a/src/box/index.h
+++ b/src/box/index.h
@@ -642,9 +642,12 @@ struct index_read_view_vtab {
 	 * Look up a tuple by a full key in a read view.
 	 *
 	 * The tuple data and size are returned in the data and size arguments.
-	 * Note, the tuple may be allocated from the fiber region so one should
-	 * call region_truncate after using the data. If the key isn't found,
-	 * the data is set to NULL.
+	 * If the key isn't found, the data is set to NULL.
+	 *
+	 * Note, unless the read_view_opts::disable_decompression flag was set
+	 * at read_view_open, the returned data may be allocated on the fiber
+	 * region, and the user is supposed to call region_truncate after using
+	 * the data.
 	 *
 	 * Returns 0 on success. On error returns -1 and sets diag.
 	 */
@@ -685,9 +688,12 @@ struct index_read_view_iterator_base {
 	 * Iterate to the next tuple in the read view.
 	 *
 	 * The tuple data and size are returned in the data and size arguments.
-	 * Note, the tuple may be allocated from the fiber region so one should
-	 * call region_truncate after using the data. On EOF the data is set to
-	 * NULL.
+	 * On EOF the data is set to NULL.
+	 *
+	 * Note, unless the read_view_opts::disable_decompression flag was set
+	 * at read_view_open, the returned data may be allocated on the fiber
+	 * region, and the user is supposed to call region_truncate after using
+	 * the data.
 	 *
 	 * Returns 0 on success. On error returns -1 and sets diag.
 	 */
diff --git a/src/box/memtx_engine.cc b/src/box/memtx_engine.cc
index 64c7e0c03c..faca74651f 100644
--- a/src/box/memtx_engine.cc
+++ b/src/box/memtx_engine.cc
@@ -1652,6 +1652,7 @@ memtx_prepare_result_tuple(struct tuple **result)
 int
 memtx_prepare_read_view_tuple(struct tuple *tuple,
 			      struct memtx_tx_snapshot_cleaner *cleaner,
+			      bool disable_decompression,
 			      const char **data, uint32_t *size)
 {
 	tuple = memtx_tx_snapshot_clarify(cleaner, tuple);
@@ -1661,8 +1662,12 @@ memtx_prepare_read_view_tuple(struct tuple *tuple,
 		return 0;
 	}
 	*data = tuple_data_range(tuple, size);
-	*data = memtx_tuple_decompress_raw(*data, *data + *size, size);
-	return *data == NULL ? -1 : 0;
+	if (!disable_decompression) {
+		*data = memtx_tuple_decompress_raw(*data, *data + *size, size);
+		if (*data == NULL)
+			return -1;
+	}
+	return 0;
 }
 
 int
diff --git a/src/box/memtx_engine.h b/src/box/memtx_engine.h
index dd5ddcc856..2fbc746857 100644
--- a/src/box/memtx_engine.h
+++ b/src/box/memtx_engine.h
@@ -284,17 +284,23 @@ memtx_prepare_result_tuple(struct tuple **result);
  * to the user.
  *
  * A pointer to the raw tuple data and its size are returned in the data and
- * size out argument. The data may be allocated from the fiber region (e.g. if
- * the original tuple is compressed) so the caller should clean up the region
- * after using the data. If the tuple should be skipped (e.g. it's not visible
- * from the read view, because it was dirty when the read view was created),
- * the data is set to NULL.
+ * size out argument.
+ *
+ * This function performs two tasks:
+ *
+ *  1. Eliminates dirty tuples using the provided snapshot cleaner created
+ *     at read_view_open. If the given tuple should be skipped, the data is
+ *     set to NULL.
+ *
+ *  2. Decompresses tuples if required, unless the disable_decompression flag
+ *     is set. Decompressed tuple data is stored on the fiber region.
  *
  * Returns 0 on success. On error returns -1 and sets diag.
  */
 int
 memtx_prepare_read_view_tuple(struct tuple *tuple,
 			      struct memtx_tx_snapshot_cleaner *cleaner,
+			      bool disable_decompression,
 			      const char **data, uint32_t *size);
 
 /**
diff --git a/src/box/memtx_hash.cc b/src/box/memtx_hash.cc
index f057ee53f3..23aab5584c 100644
--- a/src/box/memtx_hash.cc
+++ b/src/box/memtx_hash.cc
@@ -512,6 +512,8 @@ struct hash_read_view {
 	struct light_index_view view;
 	/** Used for clarifying read view tuples. */
 	struct memtx_tx_snapshot_cleaner cleaner;
+	/** See read_view_opts::disable_decompression. */
+	bool disable_decompression;
 };
 
 /** Read view iterator implementation. */
@@ -573,6 +575,7 @@ hash_read_view_iterator_next_raw(struct index_read_view_iterator *iterator,
 			return 0;
 		}
 		if (memtx_prepare_read_view_tuple(*res, &rv->cleaner,
+						  rv->disable_decompression,
 						  data, size) != 0)
 			return -1;
 		if (*data != NULL)
@@ -628,7 +631,6 @@ static struct index_read_view *
 memtx_hash_index_create_read_view(struct index *base,
 				  const struct read_view_opts *opts)
 {
-	(void)opts;
 	static const struct index_read_view_vtab vtab = {
 		.free = hash_read_view_free,
 		.get_raw = hash_read_view_get_raw,
@@ -643,6 +645,7 @@ memtx_hash_index_create_read_view(struct index *base,
 	}
 	struct space *space = space_cache_find(base->def->space_id);
 	memtx_tx_snapshot_cleaner_create(&rv->cleaner, space);
+	rv->disable_decompression = opts->disable_decompression;
 	rv->index = index;
 	index_ref(base);
 	light_index_view_create(&rv->view, &index->hash_table);
diff --git a/src/box/memtx_tree.cc b/src/box/memtx_tree.cc
index ccaeca70da..c9e73bd550 100644
--- a/src/box/memtx_tree.cc
+++ b/src/box/memtx_tree.cc
@@ -1851,6 +1851,8 @@ struct tree_read_view {
 	memtx_tree_view_t<USE_HINT> tree_view;
 	/** Used for clarifying read view tuples. */
 	struct memtx_tx_snapshot_cleaner cleaner;
+	/** See read_view_opts::disable_decompression. */
+	bool disable_decompression;
 };
 
 /** Read view iterator implementation. */
@@ -1929,6 +1931,7 @@ tree_read_view_iterator_next_raw(struct index_read_view_iterator *iterator,
 		memtx_tree_view_iterator_next(&rv->tree_view,
 					      &it->tree_iterator);
 		if (memtx_prepare_read_view_tuple(res->tuple, &rv->cleaner,
+						  rv->disable_decompression,
 						  data, size) != 0)
 			return -1;
 		if (*data != NULL)
@@ -1991,7 +1994,6 @@ static struct index_read_view *
 memtx_tree_index_create_read_view(struct index *base,
 				  const struct read_view_opts *opts)
 {
-	(void)opts;
 	static const struct index_read_view_vtab vtab = {
 		.free = tree_read_view_free<USE_HINT>,
 		.get_raw = tree_read_view_get_raw<USE_HINT>,
@@ -2007,6 +2009,7 @@ memtx_tree_index_create_read_view(struct index *base,
 	}
 	struct space *space = space_cache_find(base->def->space_id);
 	memtx_tx_snapshot_cleaner_create(&rv->cleaner, space);
+	rv->disable_decompression = opts->disable_decompression;
 	rv->index = index;
 	index_ref(base);
 	memtx_tree_view_create(&rv->tree_view, &index->tree);
diff --git a/src/box/read_view.c b/src/box/read_view.c
index 43d553cba6..0ead9cf951 100644
--- a/src/box/read_view.c
+++ b/src/box/read_view.c
@@ -49,6 +49,7 @@ read_view_opts_create(struct read_view_opts *opts)
 	opts->enable_field_names = false;
 	opts->enable_space_upgrade = false;
 	opts->enable_temporary_spaces = false;
+	opts->disable_decompression = false;
 }
 
 static void
diff --git a/src/box/read_view.h b/src/box/read_view.h
index 998e990095..ce562beb07 100644
--- a/src/box/read_view.h
+++ b/src/box/read_view.h
@@ -140,6 +140,15 @@ struct read_view_opts {
 	 * flag is set.
 	 */
 	bool enable_temporary_spaces;
+	/**
+	 * Memtx-specific. Disables decompression of tuples fetched from
+	 * the read view. Setting this flag makes the raw read view methods
+	 * (get_raw, next_raw) return a pointer to the data stored in
+	 * the read view as is, without any preprocessing or copying to
+	 * the fiber region. The user is supposed to decompress the data
+	 * encoded in the MP_COMPRESSION MsgPack extension manually.
+	 */
+	bool disable_decompression;
 };
 
 /** Sets read view options to default values. */
-- 
GitLab