From cb5490cf8d2fda7840ded7247b0c95b1f3010e56 Mon Sep 17 00:00:00 2001 From: An Long Date: Sat, 26 Sep 2026 23:11:05 +0900 Subject: [PATCH 1/2] Update Hbase.thrift and support cache_blocks in Table.scan() --- happybase/Hbase.thrift | 80 ++++++++++++++++++++++++++++++++---------- happybase/table.py | 12 ++++++- tests/test_api.py | 3 ++ 3 files changed, 76 insertions(+), 19 deletions(-) diff --git a/happybase/Hbase.thrift b/happybase/Hbase.thrift index e9836cd..8b204b3 100644 --- a/happybase/Hbase.thrift +++ b/happybase/Hbase.thrift @@ -75,7 +75,7 @@ struct ColumnDescriptor { 6:i32 bloomFilterVectorSize = 0, 7:i32 bloomFilterNbHashes = 0, 8:bool blockCacheEnabled = 0, - 9:i32 timeToLive = -1 + 9:i32 timeToLive = 0x7fffffff } /** @@ -150,7 +150,8 @@ struct TScan { 6:optional Text filterString, 7:optional i32 batchSize, 8:optional bool sortColumns, - 9:optional bool reversed + 9:optional bool reversed, + 10:optional bool cacheBlocks } /** @@ -173,6 +174,7 @@ struct TAppend { */ exception IOError { 1:string message + 2:bool canRetry } /** @@ -191,6 +193,30 @@ exception AlreadyExists { 1:string message } +/** + * Specify type of thrift server: thrift and thrift2 + */ +enum TThriftServerType { + ONE = 1, + TWO = 2 +} + +enum TPermissionScope { + TABLE = 0, + NAMESPACE = 1 +} + +/** + * TAccessControlEntity for permission control + */ +struct TAccessControlEntity { + 1: required string username + 2: required TPermissionScope scope + 4: required string actions + 5: optional Bytes tableName + 6: optional string nsName +} + // // Service // @@ -235,6 +261,14 @@ service Hbase { list getTableNames() throws (1:IOError io) + /** + * List all the userspace tables and their enabled or disabled flags. + * + * @return list of tables with is enabled flags + */ + map getTableNamesWithIsTableEnabled() + throws (1:IOError io) + /** * List all the column families assoicated with a table. * @@ -906,22 +940,6 @@ service Hbase { 1:ScannerID id ) throws (1:IOError io, 2:IllegalArgument ia) - /** - * Get the row just before the specified one. - * - * @return value for specified row/column - */ - list getRowOrBefore( - /** name of table */ - 1:Text tableName, - - /** row key */ - 2:Text row, - - /** column name */ - 3:Text family - ) throws (1:IOError io) - /** * Get the regininfo for the specified row. It scans * the metatable to find region's start and end keys. @@ -972,4 +990,30 @@ service Hbase { /** Mutation attributes */ 7:map attributes ) throws (1:IOError io, 2:IllegalArgument ia) + + /** + * Get the type of this thrift server. + * + * @return the type of this thrift server + */ + TThriftServerType getThriftServerType() + + /** + * Returns the cluster ID for this cluster. + */ + string getClusterId() + + /** + * Grant permissions in namespace or table level. + */ + bool grant( + 1: required TAccessControlEntity info + ) throws (1: IOError io) + + /** + * Revoke permissions in namespace or table level. + */ + bool revoke( + 1: required TAccessControlEntity info + ) throws (1: IOError io) } diff --git a/happybase/table.py b/happybase/table.py index bc90c5d..1a7c1c5 100644 --- a/happybase/table.py +++ b/happybase/table.py @@ -222,7 +222,8 @@ def cells(self, row, column, versions=None, timestamp=None, def scan(self, row_start=None, row_stop=None, row_prefix=None, columns=None, filter=None, timestamp=None, include_timestamp=False, batch_size=1000, scan_batching=None, - limit=None, sorted_columns=False, reverse=False): + limit=None, sorted_columns=False, reverse=False, + cache_blocks=None): """Create a scanner for data in the table. This method returns an iterable that can be used for looping over the @@ -273,6 +274,10 @@ def scan(self, row_start=None, row_stop=None, row_prefix=None, Note that the start of the range is inclusive, while the end is exclusive just as in the forward scan. + The optional `cache_blocks` translates to `Scan.setCacheBlocks()` + at the Java side. Set it to `False` to avoid filling the block + cache on the region servers, e.g. for large full table scans. + **Compatibility notes:** * The `filter` argument is only available when using HBase 0.92 @@ -285,6 +290,9 @@ def scan(self, row_start=None, row_stop=None, row_prefix=None, * The `reverse` argument is only available when using HBase 0.98 (or up). + .. versionadded:: 1.4.0 + `cache_blocks` argument + .. versionadded:: 1.1.0 `reverse` argument @@ -306,6 +314,7 @@ def scan(self, row_start=None, row_stop=None, row_prefix=None, :param int limit: max number of rows to return :param bool sorted_columns: whether to return sorted columns :param bool reverse: whether to perform scan in reverse + :param bool cache_blocks: whether to use the server side block cache :return: generator yielding the rows matching the scan :rtype: iterable of `(row_key, row_data)` tuples @@ -397,6 +406,7 @@ def scan(self, row_start=None, row_stop=None, row_prefix=None, batchSize=scan_batching, sortColumns=sorted_columns, reversed=reverse, + cacheBlocks=cache_blocks, ) scan_id = self.connection.client.scannerOpenWithScan( self.name, scan, {}) diff --git a/tests/test_api.py b/tests/test_api.py index da1d2fe..7b75126 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -402,6 +402,9 @@ def calc_len(scanner): scanner = table.scan(row_prefix=b'row-scan-b', batch_size=5, limit=10) assert 10 == calc_len(scanner) + scanner = table.scan(row_prefix=b'row-scan-b', cache_blocks=False) + assert 2000 == calc_len(scanner) + scanner = table.scan(timestamp=123) assert 0 == calc_len(scanner) From 206e4e49cc68db8e895cc0f062858df0cc5ad2ad Mon Sep 17 00:00:00 2001 From: An Long Date: Mon, 28 Sep 2026 21:08:02 +0900 Subject: [PATCH 2/2] Default cache_blocks to True --- happybase/table.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/happybase/table.py b/happybase/table.py index 1a7c1c5..f1ea350 100644 --- a/happybase/table.py +++ b/happybase/table.py @@ -223,7 +223,7 @@ def scan(self, row_start=None, row_stop=None, row_prefix=None, columns=None, filter=None, timestamp=None, include_timestamp=False, batch_size=1000, scan_batching=None, limit=None, sorted_columns=False, reverse=False, - cache_blocks=None): + cache_blocks=True): """Create a scanner for data in the table. This method returns an iterable that can be used for looping over the @@ -274,9 +274,10 @@ def scan(self, row_start=None, row_stop=None, row_prefix=None, Note that the start of the range is inclusive, while the end is exclusive just as in the forward scan. - The optional `cache_blocks` translates to `Scan.setCacheBlocks()` - at the Java side. Set it to `False` to avoid filling the block - cache on the region servers, e.g. for large full table scans. + The `cache_blocks` argument translates to `Scan.setCacheBlocks()` + at the Java side and defaults to `True`. Set it to `False` to avoid + filling the block cache on the region servers, e.g. for large full + table scans. **Compatibility notes:**