[tableapi] support hbase api

This commit is contained in:
xj0 2021-10-29 15:27:51 +08:00 committed by LINxiansheng
parent d1707e6a19
commit 97b4a6afb8
36 changed files with 11128 additions and 51 deletions

View File

@ -578,6 +578,7 @@ PCODE_DEF(OB_TABLE_API_LOGIN, 0x1101)
PCODE_DEF(OB_TABLE_API_EXECUTE, 0x1102)
PCODE_DEF(OB_TABLE_API_BATCH_EXECUTE, 0x1103)
PCODE_DEF(OB_TABLE_API_EXECUTE_QUERY, 0x1104)
PCODE_DEF(OB_TABLE_API_QUERY_AND_MUTATE, 0x1105)
// Event Job API
PCODE_DEF(OB_RUN_EVENT_JOB, 0x1201)

View File

@ -255,8 +255,17 @@ ob_set_subtarget(ob_server table
table/ob_table_rpc_processor.cpp
table/ob_table_service.cpp
table/ob_table_api_row_iterator.cpp
table/ob_table_query_and_mutate_processor.cpp
table/ob_htable_filter_operator.cpp
table/ob_htable_filter_parser.cpp
table/ob_htable_utils.cpp
table/ob_htable_filters.cpp
table/htable_filter_tab.cxx
table/htable_filter_lex.cxx
)
set_source_files_properties(table/htable_filter_lex.cxx PROPERTIES COMPILE_FLAGS -Wno-null-conversion)
ob_server_add_pchs(observer
ob_server_struct.h
ob_uniq_task_queue.h

View File

@ -41,6 +41,7 @@
#include "observer/table/ob_table_execute_processor.h"
#include "observer/table/ob_table_batch_execute_processor.h"
#include "observer/table/ob_table_query_processor.h"
#include "observer/table/ob_table_query_and_mutate_processor.h"
using namespace oceanbase;
using namespace oceanbase::observer;
@ -136,6 +137,7 @@ void oceanbase::observer::init_srv_xlator_for_others(ObSrvRpcXlator* xlator)
RPC_PROCESSOR(ObTableApiExecuteP, gctx_);
RPC_PROCESSOR(ObTableBatchExecuteP, gctx_);
RPC_PROCESSOR(ObTableQueryP, gctx_);
RPC_PROCESSOR(ObTableQueryAndMutateP, gctx_);
// HA GTS
RPC_PROCESSOR(ObHaGtsPingRequestP, gctx_);

View File

@ -0,0 +1,11 @@
#!/bin/bash
export PATH=/usr/local/bin:$PATH
# generate sql_parser
bison -v -Werror --defines=../../../src/observer/table/htable_filter_tab.hxx --output=../../../src/observer/table/htable_filter_tab.cxx ../../../src/observer/table/htable_filter_tab.yxx
if [ $? -ne 0 ]
then
echo yacc error[$?], abort.
exit 1
fi
flex --header-file="../../../src/observer/table/htable_filter_lex.hxx" --outfile="../../../src/observer/table/htable_filter_lex.cxx" ../../../src/observer/table/htable_filter_lex.lxx

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,354 @@
#ifndef ob_hfilter_HEADER_H
#define ob_hfilter_HEADER_H 1
#define ob_hfilter_IN_HEADER 1
#line 6 "../../../src/observer/table/htable_filter_lex.hxx"
#line 7 "../../../src/observer/table/htable_filter_lex.lxx"
#define USING_LOG_PREFIX SERVER
#include "observer/table/ob_htable_filter_parser.h"
#include "observer/table/ob_htable_filters.h"
#include "observer/table/htable_filter_tab.hxx"
using namespace oceanbase::common;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#line 18 "../../../src/observer/table/htable_filter_lex.hxx"
#define YY_INT_ALIGNED short int
/* A lexical scanner generated by flex */
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
#define YY_FLEX_SUBMINOR_VERSION 35
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
/* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
/* end standard C headers. */
/* flex integer type definitions */
#ifndef FLEXINT_H
#define FLEXINT_H
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
* if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#endif
#include <inttypes.h>
typedef int8_t flex_int8_t;
typedef uint8_t flex_uint8_t;
typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef int flex_int32_t;
typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
#endif /* ! C99 */
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
#ifndef INT16_MIN
#define INT16_MIN (-32767-1)
#endif
#ifndef INT32_MIN
#define INT32_MIN (-2147483647-1)
#endif
#ifndef INT8_MAX
#define INT8_MAX (127)
#endif
#ifndef INT16_MAX
#define INT16_MAX (32767)
#endif
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
#ifndef UINT8_MAX
#define UINT8_MAX (255U)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (65535U)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
#endif
#endif /* ! FLEXINT_H */
#ifdef __cplusplus
/* The "const" storage-class-modifier is valid. */
#define YY_USE_CONST
#else /* ! __cplusplus */
/* C99 requires __STDC__ to be defined as 1. */
#if defined (__STDC__)
#define YY_USE_CONST
#endif /* defined (__STDC__) */
#endif /* ! __cplusplus */
#ifdef YY_USE_CONST
#define yyconst const
#else
#define yyconst
#endif
/* An opaque pointer. */
#ifndef YY_TYPEDEF_YY_SCANNER_T
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
/* For convenience, these vars (plus the bison vars far below)
are macros in the reentrant scanner. */
#define yyin yyg->yyin_r
#define yyout yyg->yyout_r
#define yyextra yyg->yyextra_r
#define yyleng yyg->yyleng_r
#define yytext yyg->yytext_r
#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
#define yy_flex_debug yyg->yy_flex_debug_r
/* Size of default input buffer. */
#ifndef YY_BUF_SIZE
#define YY_BUF_SIZE 16384
#endif
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef size_t yy_size_t;
#endif
#ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state
{
FILE *yy_input_file;
char *yy_ch_buf; /* input buffer */
char *yy_buf_pos; /* current position in input buffer */
/* Size of input buffer in bytes, not including room for EOB
* characters.
*/
yy_size_t yy_buf_size;
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
int yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
* delete it.
*/
int yy_is_our_buffer;
/* Whether this is an "interactive" input source; if so, and
* if we're using stdio for input, then we want to use getc()
* instead of fread(), to make sure we stop fetching input after
* each newline.
*/
int yy_is_interactive;
/* Whether we're considered to be at the beginning of a line.
* If so, '^' rules will be active on the next match, otherwise
* not.
*/
int yy_at_bol;
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
int yy_fill_buffer;
int yy_buffer_status;
};
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
void ob_hfilter_restart (FILE *input_file ,yyscan_t yyscanner );
void ob_hfilter__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
YY_BUFFER_STATE ob_hfilter__create_buffer (FILE *file,int size ,yyscan_t yyscanner );
void ob_hfilter__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
void ob_hfilter__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
void ob_hfilter_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
void ob_hfilter_pop_buffer_state (yyscan_t yyscanner );
YY_BUFFER_STATE ob_hfilter__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
YY_BUFFER_STATE ob_hfilter__scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
YY_BUFFER_STATE ob_hfilter__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
void *ob_hfilter_alloc (yy_size_t ,yyscan_t yyscanner );
void *ob_hfilter_realloc (void *,yy_size_t ,yyscan_t yyscanner );
void ob_hfilter_free (void * ,yyscan_t yyscanner );
/* Begin user sect3 */
#define ob_hfilter_wrap(n) 1
#define YY_SKIP_YYWRAP
#define yytext_ptr yytext_r
#ifdef YY_HEADER_EXPORT_START_CONDITIONS
#define INITIAL 0
#define IN_STRING 1
#endif
#ifndef YY_NO_UNISTD_H
/* Special case for "unistd.h", since it is non-ANSI. We include it way
* down here because we want the user's section 1 to have been scanned first.
* The user has a chance to override it with an option.
*/
#include <unistd.h>
#endif
#define YY_EXTRA_TYPE oceanbase::table::ObHTableFilterParser *
int ob_hfilter_lex_init (yyscan_t* scanner);
int ob_hfilter_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
/* Accessor methods to globals.
These are made visible to non-reentrant scanners for convenience. */
int ob_hfilter_lex_destroy (yyscan_t yyscanner );
int ob_hfilter_get_debug (yyscan_t yyscanner );
void ob_hfilter_set_debug (int debug_flag ,yyscan_t yyscanner );
YY_EXTRA_TYPE ob_hfilter_get_extra (yyscan_t yyscanner );
void ob_hfilter_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
FILE *ob_hfilter_get_in (yyscan_t yyscanner );
void ob_hfilter_set_in (FILE * in_str ,yyscan_t yyscanner );
FILE *ob_hfilter_get_out (yyscan_t yyscanner );
void ob_hfilter_set_out (FILE * out_str ,yyscan_t yyscanner );
int ob_hfilter_get_leng (yyscan_t yyscanner );
char *ob_hfilter_get_text (yyscan_t yyscanner );
int ob_hfilter_get_lineno (yyscan_t yyscanner );
void ob_hfilter_set_lineno (int line_number ,yyscan_t yyscanner );
YYSTYPE * ob_hfilter_get_lval (yyscan_t yyscanner );
void ob_hfilter_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
YYLTYPE *ob_hfilter_get_lloc (yyscan_t yyscanner );
void ob_hfilter_set_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
/* Macros after this point can all be overridden by user definitions in
* section 1.
*/
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int ob_hfilter_wrap (yyscan_t yyscanner );
#else
extern int ob_hfilter_wrap (yyscan_t yyscanner );
#endif
#endif
#ifndef yytext_ptr
static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
#endif
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
#endif
#ifndef YY_NO_INPUT
#endif
/* Amount of stuff to slurp up with each read. */
#ifndef YY_READ_BUF_SIZE
#define YY_READ_BUF_SIZE 8192
#endif
/* Number of entries by which start-condition stack grows. */
#ifndef YY_START_STACK_INCR
#define YY_START_STACK_INCR 25
#endif
/* Default declaration of generated scanner - a define so the user can
* easily add parameters.
*/
#ifndef YY_DECL
#define YY_DECL_IS_OURS 1
extern int ob_hfilter_lex \
(YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
#define YY_DECL int ob_hfilter_lex \
(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
#endif /* !YY_DECL */
/* yy_get_previous_state - get the state just before the EOB char was reached */
#undef YY_NEW_FILE
#undef YY_FLUSH_BUFFER
#undef yy_set_bol
#undef yy_new_buffer
#undef yy_set_interactive
#undef YY_DO_BEFORE_ACTION
#ifdef YY_DECL_IS_OURS
#undef YY_DECL_IS_OURS
#undef YY_DECL
#endif
#line 106 "../../../src/observer/table/htable_filter_lex.lxx"
#line 353 "../../../src/observer/table/htable_filter_lex.hxx"
#undef ob_hfilter_IN_HEADER
#endif /* ob_hfilter_HEADER_H */

View File

@ -0,0 +1,109 @@
%option yylineno case-insensitive reentrant
%option bison-bridge bison-locations
%option noyyalloc noyyrealloc noyyfree noyywrap nounput noinput
%option extra-type="oceanbase::table::ObHTableFilterParser *"
%option prefix="ob_hfilter_"
%top{
#define USING_LOG_PREFIX SERVER
#include "observer/table/ob_htable_filter_parser.h"
#include "observer/table/ob_htable_filters.h"
#include "observer/table/htable_filter_tab.hxx"
using namespace oceanbase::common;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
}
%x IN_STRING
ID ([A-Za-z0-9$_]*)
INT [0-9]+
SQUOTE '
%%
/* rules */
SKIP { return SKIP; }
WHILE { return WHILE; }
AND { return AND; }
OR { return OR; }
"=" { return EQUAL; }
"!=" { return NOT_EQUAL; }
">=" { return GREATER_OR_EQUAL; }
">" { return GREATER; }
"<=" { return LESS_OR_EQUAL; }
"<" { return LESS; }
NO_OP { return NO_OP; }
TRUE {
yylval->ival = 1;
return BOOL_VALUE;
}
FALSE {
yylval->ival = 0;
return BOOL_VALUE;
}
{INT} {
errno = 0;
yylval->lval = strtoll(yytext, NULL, 10);
if (ERANGE == errno)
{
ob_hfilter_error(yylloc, yyextra, "integar value out of range");
}
return INT_VALUE;
}
{SQUOTE} {
BEGIN(IN_STRING);
char *buf = static_cast<char*>(yyextra->alloc(yyextra->get_input_len()+1));
if (NULL == buf) {
yyextra->error_code_ = oceanbase::common::OB_ALLOCATE_MEMORY_FAILED;
ob_hfilter_error(yylloc, yyextra, "no memory");
return ERROR;
}
yylval->sval.len_ = 0;
yylval->sval.str_ = buf;
}
<IN_STRING>[^']+ {
memcpy(yylval->sval.str_+yylval->sval.len_, yytext, yyleng);
yylval->sval.len_ += yyleng;
}
<IN_STRING>{SQUOTE}{SQUOTE} {
yylval->sval.str_[yylval->sval.len_++] = '\'';
}
<IN_STRING>{SQUOTE} {
BEGIN(INITIAL);
return STRING_VALUE;
}
<IN_STRING><<EOF>> {
ob_hfilter_error(yylloc, yyextra, "unterminated quoted string");
return ERROR;
}
RowFilter { return RowFilter; }
ValueFilter { return ValueFilter; }
QualifierFilter { return QualifierFilter; }
SingleColumnValueFilter { return SingleColumnValueFilter; }
PageFilter { return PageFilter; }
ColumnCountGetFilter { return ColumnCountGetFilter; }
CheckAndMutateFilter { return CheckAndMutateFilter; }
PrefixFilter { return PrefixFilter; }
[(),] {
return yytext[0];
}
[ \t\r\n] {/*skip*/}
<<EOF>> {
return END;
}
. {
ob_hfilter_error(yylloc, yyextra, "mystery charactor '%c'", *yytext);
return ERROR;
}
%%
/* user code */
#pragma GCC diagnostic pop

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,110 @@
/* A Bison parser, made by GNU Bison 2.4.1. */
/* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
END = 0,
RowFilter = 258,
ValueFilter = 259,
QualifierFilter = 260,
SingleColumnValueFilter = 261,
PageFilter = 262,
ColumnCountGetFilter = 263,
CheckAndMutateFilter = 264,
PrefixFilter = 265,
LESS = 266,
LESS_OR_EQUAL = 267,
EQUAL = 268,
NOT_EQUAL = 269,
GREATER = 270,
GREATER_OR_EQUAL = 271,
NO_OP = 272,
BOOL_VALUE = 273,
STRING_VALUE = 274,
INT_VALUE = 275,
OR = 276,
AND = 277,
WHILE = 278,
SKIP = 279,
ERROR = 280
};
#endif
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
/* Line 1676 of yacc.c */
#line 23 "../../../src/observer/table/htable_filter_tab.yxx"
int32_t ival;
int64_t lval;
oceanbase::table::hfilter::CompareOperator cmp_op;
oceanbase::table::ObHTableFilterParser::SimpleString sval;
oceanbase::table::hfilter::Filter *fval;
/* Line 1676 of yacc.c */
#line 88 "../../../src/observer/table/htable_filter_tab.hxx"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
typedef struct YYLTYPE
{
int first_line;
int first_column;
int last_line;
int last_column;
} YYLTYPE;
# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
# define YYLTYPE_IS_DECLARED 1
# define YYLTYPE_IS_TRIVIAL 1
#endif

View File

@ -0,0 +1,349 @@
/* Location tracking. */
%locations
/* Pure yylex. */
%define api.pure
/* Pure yyparse. */
%parse-param {oceanbase::table::ObHTableFilterParser *parse_ctx}
%verbose
%error-verbose
%name-prefix "ob_hfilter_"
%{
#define USING_LOG_PREFIX SERVER
#include <stdint.h>
#include "observer/table/ob_htable_filters.h"
#include "observer/table/ob_htable_filter_parser.h"
#include "observer/table/htable_filter_lex.hxx"
#define YYDEBUG 1
#define YYLEX_PARAM (parse_ctx->scanner_)
using namespace oceanbase::table;
using namespace oceanbase::common;
%}
// Symbols.
%union
{
int32_t ival;
int64_t lval;
oceanbase::table::hfilter::CompareOperator cmp_op;
oceanbase::table::ObHTableFilterParser::SimpleString sval;
oceanbase::table::hfilter::Filter *fval;
};
%token RowFilter ValueFilter QualifierFilter SingleColumnValueFilter PageFilter ColumnCountGetFilter
%token CheckAndMutateFilter PrefixFilter
%token LESS LESS_OR_EQUAL EQUAL NOT_EQUAL GREATER GREATER_OR_EQUAL NO_OP
%token <ival> BOOL_VALUE
%token <sval> STRING_VALUE
%token <lval> INT_VALUE
%left OR
%left AND
%right SKIP WHILE
%token END 0 "end of file"
%token ERROR
%type <fval> simple_filter filter result_filter
%type <sval> family qualifier comparator
%type <cmp_op> compare_op
%start result_filter
%%
////////////////////////////////////////////////////////////////
result_filter: filter END {
parse_ctx->set_result_filter($1);
YYACCEPT;
}
;
filter:
filter AND filter %prec AND
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
hfilter::FilterListBase *filter_list = nullptr;
$$ = filter_list = OB_NEWx(hfilter::FilterListAND, parse_ctx->allocator(),
hfilter::FilterListBase::Operator::MUST_PASS_ALL);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
} else if (OB_FAIL(filter_list->add_filter($1))) {
LOG_WARN("failed to add filter to list", K(ret));
} else if (OB_FAIL(filter_list->add_filter($3))) {
LOG_WARN("failed to add filter to list", K(ret));
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse FilterList with AND");
YYABORT;
}
}
| filter OR filter %prec OR
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
hfilter::FilterListBase *filter_list = nullptr;
$$ = filter_list = OB_NEWx(hfilter::FilterListOR, parse_ctx->allocator(),
hfilter::FilterListBase::Operator::MUST_PASS_ONE);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
} else if (OB_FAIL(filter_list->add_filter($1))) {
LOG_WARN("failed to add filter to list", K(ret));
} else if (OB_FAIL(filter_list->add_filter($3))) {
LOG_WARN("failed to add filter to list", K(ret));
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse FilterList with AND");
YYABORT;
}
}
| SKIP filter %prec SKIP
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
$$ = OB_NEWx(hfilter::SkipFilter, parse_ctx->allocator(), $2);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse SkipFilter");
YYABORT;
}
}
| WHILE filter %prec WHILE
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
$$ = OB_NEWx(hfilter::WhileMatchFilter, parse_ctx->allocator(), $2);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse WhileFilter");
YYABORT;
}
}
| simple_filter
{
$$ = $1;
}
;
simple_filter:
'(' filter ')'
{ $$ = $2; }
| RowFilter '(' compare_op ',' comparator ')'
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
hfilter::Comparable *comparable = nullptr;
if (OB_FAIL(parse_ctx->create_comparator($5, comparable))) {
LOG_WARN("failed to create comparator", K(ret));
} else {
$$ = OB_NEWx(hfilter::RowFilter, parse_ctx->allocator(), $3, comparable);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(static_cast<hfilter::RowFilter*>($$)->check_arguments())) {
LOG_WARN("failed to check arguments", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
}
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse RowFilter");
YYABORT;
}
}
| QualifierFilter '(' compare_op ',' comparator ')'
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
hfilter::Comparable *comparable = nullptr;
if (OB_FAIL(parse_ctx->create_comparator($5, comparable))) {
LOG_WARN("failed to create comparator", K(ret));
} else {
$$ = OB_NEWx(hfilter::QualifierFilter, parse_ctx->allocator(), $3, comparable);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(static_cast<hfilter::QualifierFilter*>($$)->check_arguments())) {
LOG_WARN("failed to check arguments", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
}
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse QualifierFilter");
YYABORT;
}
}
| ValueFilter '(' compare_op ',' comparator ')'
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
hfilter::Comparable *comparable = nullptr;
if (OB_FAIL(parse_ctx->create_comparator($5, comparable))) {
LOG_WARN("failed to create comparator", K(ret));
} else {
$$ = OB_NEWx(hfilter::ValueFilter, parse_ctx->allocator(), $3, comparable);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(static_cast<hfilter::ValueFilter*>($$)->check_arguments())) {
LOG_WARN("failed to check arguments", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
}
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse ValueFilter");
YYABORT;
}
}
| PrefixFilter '(' STRING_VALUE ')'
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
hfilter::Comparable *comparable = nullptr;
if (OB_FAIL(parse_ctx->create_prefix_comparator($3, comparable))) {
LOG_WARN("failed to create comparator", K(ret));
} else {
$$ = OB_NEWx(hfilter::RowFilter, parse_ctx->allocator(), hfilter::CompareOperator::EQUAL, comparable);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(static_cast<hfilter::RowFilter*>($$)->check_arguments())) {
LOG_WARN("failed to check arguments", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
}
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse PrefixFilter");
YYABORT;
}
}
| SingleColumnValueFilter '(' family ',' qualifier ',' compare_op ',' comparator ',' BOOL_VALUE ',' BOOL_VALUE ')'
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
hfilter::Comparable *comparable = nullptr;
if (OB_FAIL(parse_ctx->create_comparator($9, comparable))) {
LOG_WARN("failed to create comparator", K(ret));
} else {
ObString family($3.len_, $3.str_);
ObString qualifier($5.len_, $5.str_);
bool filter_if_missing = ($11 == 1);
bool latest_version_only = ($13 == 1);
hfilter::SingleColumnValueFilter *filter = NULL;
$$ = filter = OB_NEWx(hfilter::SingleColumnValueFilter, parse_ctx->allocator(), family, qualifier, $7, comparable);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
} else {
filter->set_filter_if_missing(filter_if_missing);
filter->set_latest_version_only(latest_version_only);
}
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse SingleColumnValueFilter");
YYABORT;
}
}
| SingleColumnValueFilter '(' family ',' qualifier ',' compare_op ',' comparator ')'
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
hfilter::Comparable *comparable = nullptr;
if (OB_FAIL(parse_ctx->create_comparator($9, comparable))) {
LOG_WARN("failed to create comparator", K(ret));
} else {
ObString family($3.len_, $3.str_);
ObString qualifier($5.len_, $5.str_);
const bool filter_if_missing = false;
const bool latest_version_only = true;
hfilter::SingleColumnValueFilter *filter = NULL;
$$ = filter = OB_NEWx(hfilter::SingleColumnValueFilter, parse_ctx->allocator(), family, qualifier, $7, comparable);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
} else {
filter->set_filter_if_missing(filter_if_missing);
filter->set_latest_version_only(latest_version_only);
}
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse SingleColumnValueFilter");
YYABORT;
}
}
| PageFilter '(' INT_VALUE ')'
{
int &ret = parse_ctx->error_code_ = OB_NOT_SUPPORTED;
UNUSED(ret);
ob_hfilter_error(&(@$), parse_ctx, "PageFilter not supported");
YYABORT;
}
| ColumnCountGetFilter '(' INT_VALUE ')'
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
$$ = OB_NEWx(hfilter::ColumnCountGetFilter, parse_ctx->allocator(), $3);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse ColumnCountGetFilter");
YYABORT;
}
}
| CheckAndMutateFilter '(' compare_op ',' comparator ',' family ',' qualifier ',' BOOL_VALUE')'
{
int &ret = parse_ctx->error_code_ = OB_SUCCESS;
hfilter::Comparable *comparable = nullptr;
if (OB_FAIL(parse_ctx->create_comparator($5, comparable))) {
LOG_WARN("failed to create comparator", K(ret));
} else {
const ObString family($7.len_, $7.str_);
const ObString qualifier($9.len_, $9.str_);
const bool value_is_null = ($11 == 1);
hfilter::CheckAndMutateFilter *filter = NULL;
$$ = filter = OB_NEWx(hfilter::CheckAndMutateFilter, parse_ctx->allocator(), family, qualifier, $3, comparable, value_is_null);
if (nullptr == $$) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(parse_ctx->store_filter($$))) {
LOG_WARN("failed to store filter", K(ret));
}
}
if (OB_SUCCESS != ret) {
ob_hfilter_error(&(@$), parse_ctx, "failed to parse CheckAndMutateFilter");
YYABORT;
}
}
;
family:
STRING_VALUE { $$ = $1; }
;
qualifier:
STRING_VALUE { $$ = $1; }
;
compare_op:
LESS { $$ = hfilter::CompareOperator::LESS; }
| LESS_OR_EQUAL { $$ = hfilter::CompareOperator::LESS_OR_EQUAL; }
| EQUAL { $$ = hfilter::CompareOperator::EQUAL; }
| NOT_EQUAL { $$ = hfilter::CompareOperator::NOT_EQUAL; }
| GREATER { $$ = hfilter::CompareOperator::GREATER; }
| GREATER_OR_EQUAL { $$ = hfilter::CompareOperator::GREATER_OR_EQUAL; }
| NO_OP { $$ = hfilter::CompareOperator::NO_OP; }
;
comparator:
STRING_VALUE
{ $$ = $1; }
;
%%

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,253 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef _OB_HTABLE_FILTER_OPERATOR_H
#define _OB_HTABLE_FILTER_OPERATOR_H 1
#include "lib/string/ob_string.h"
#include "lib/container/ob_array.h"
#include "share/table/ob_table.h"
#include "share/table/ob_table_rpc_struct.h"
#include "common/row/ob_row_iterator.h"
#include "ob_htable_utils.h"
#include "ob_htable_filter_parser.h"
#include "ob_htable_filters.h"
#include <utility>
namespace oceanbase
{
namespace table
{
class ObHColumnDescriptor final
{
public:
ObHColumnDescriptor()
:time_to_live_(0)
{}
int from_string(const common::ObString &str);
void set_time_to_live(int32_t v) { time_to_live_ = v; }
int32_t get_time_to_live() const { return time_to_live_; }
private:
int32_t time_to_live_; // Time-to-live of cell contents, in seconds.
};
enum class ObHTableMatchCode
{
INCLUDE = 0,
INCLUDE_AND_SEEK_NEXT_COL = 1,
INCLUDE_AND_SEEK_NEXT_ROW = 2,
SKIP = 3,
SEEK_NEXT_COL = 4,
SEEK_NEXT_ROW = 5,
SEEK_NEXT_USING_HINT = 6,
DONE = 7,
DONE_SCAN = 8,
DONE_REVERSE_SCAN = 9,
};
// Interface ObHTableColumnTracker
class ObHTableColumnTracker
{
public:
// types and constants
typedef std::pair<common::ObString, int32_t> ColumnCount;
class ColumnCountComparator;
class ColumnCountReverseComparator;
public:
ObHTableColumnTracker()
:max_versions_(1),
min_versions_(0),
oldest_stamp_(0)
{}
virtual ~ObHTableColumnTracker() {}
virtual int init(const table::ObHTableFilter &htable_filter, common::ObQueryFlag::ScanOrder &scan_order) = 0;
virtual int check_column(const ObHTableCell &cell, ObHTableMatchCode &match_code) = 0;
virtual int check_versions(const ObHTableCell &cell, ObHTableMatchCode &match_code) = 0;
virtual const ColumnCount *get_curr_column() const = 0;
virtual void reset() = 0;
virtual bool done() const = 0;
virtual int get_next_column_or_row(const ObHTableCell &cell, ObHTableMatchCode &match_code) = 0;
virtual common::ObQueryFlag::ScanOrder get_scan_order() { return tracker_scan_order_; }
virtual void set_scan_order(common::ObQueryFlag::ScanOrder tracker_scan_order) { tracker_scan_order_ = tracker_scan_order; }
// Give the tracker a chance to declare it's done based on only the timestamp.
bool is_done(int64_t timestamp) const;
void set_ttl(int32_t ttl_value);
protected:
int32_t max_versions_; // default: 1
int32_t min_versions_; // default: 0
int64_t oldest_stamp_; // default: 0
common::ObQueryFlag::ScanOrder tracker_scan_order_;
protected:
bool is_expired(int64_t timestamp) const { return (-timestamp) < oldest_stamp_; }
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObHTableColumnTracker);
};
class ObHTableExplicitColumnTracker: public ObHTableColumnTracker
{
public:
ObHTableExplicitColumnTracker();
virtual ~ObHTableExplicitColumnTracker() {}
virtual int init(const table::ObHTableFilter &htable_filter, common::ObQueryFlag::ScanOrder &scan_order) override;
virtual int check_column(const ObHTableCell &cell, ObHTableMatchCode &match_code) override;
virtual int check_versions(const ObHTableCell &cell, ObHTableMatchCode &match_code) override;
virtual int get_next_column_or_row(const ObHTableCell &cell, ObHTableMatchCode &match_code) override;
virtual const ColumnCount *get_curr_column() const override { return curr_column_; }
virtual void reset() override;
virtual bool done() const override;
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObHTableExplicitColumnTracker);
// function members
void done_with_column(const ObHTableCell &cell);
ObHTableMatchCode check_version(int64_t timestamp);
private:
common::ObSEArray<ColumnCount, common::OB_DEFAULT_SE_ARRAY_COUNT> columns_;
int64_t curr_column_idx_;
ColumnCount *curr_column_;
int32_t current_count_;
};
class ObHTableWildcardColumnTracker: public ObHTableColumnTracker
{
public:
ObHTableWildcardColumnTracker();
virtual ~ObHTableWildcardColumnTracker() {}
virtual int init(const table::ObHTableFilter &htable_filter, common::ObQueryFlag::ScanOrder &scan_order) override;
virtual int check_column(const ObHTableCell &cell, ObHTableMatchCode &match_code) override;
virtual int check_versions(const ObHTableCell &cell, ObHTableMatchCode &match_code) override;
virtual int get_next_column_or_row(const ObHTableCell &cell, ObHTableMatchCode &match_code) override;
virtual const ColumnCount *get_curr_column() const override { return NULL; }
virtual void reset() override;
virtual bool done() const override { return false; }
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObHTableWildcardColumnTracker);
// function members
int reset_cell(const ObHTableCell &cell);
ObHTableMatchCode check_version(int64_t timestamp);
private:
// states
common::ObArenaAllocator allocator_;
ObString current_qualifier_;
int32_t current_count_;
};
class ObHTableScanMatcher
{
public:
explicit ObHTableScanMatcher(const table::ObHTableFilter &htable_filter, ObHTableColumnTracker *column_tracker = nullptr);
virtual ~ObHTableScanMatcher() {}
void init(ObHTableColumnTracker *tracker, table::hfilter::Filter *hfilter) { column_tracker_ = tracker; hfilter_ = hfilter; }
void set_hfilter(table::hfilter::Filter *hfilter) { hfilter_ = hfilter; }
int match(const ObHTableCell &cell, ObHTableMatchCode &match_code);
int create_key_for_next_col(common::ObArenaAllocator &allocator, const ObHTableCell &cell, ObHTableCell *&next_cell);
const ObHTableCell* get_curr_row() const;
void clear_curr_row() { curr_row_.set_ob_row(NULL); }
int set_to_new_row(const ObHTableCell &curr_row);
bool is_curr_row_empty() const { return NULL == curr_row_.get_ob_row(); }
ObHTableMatchCode merge_filter_return_code(const ObHTableCell &cell,
const ObHTableMatchCode match_code,
hfilter::Filter::ReturnCode filter_rc);
private:
DISALLOW_COPY_AND_ASSIGN(ObHTableScanMatcher);
int pre_check(const ObHTableCell &cell, ObHTableMatchCode &match_code, bool &need_match_column);
int match_column(const ObHTableCell &cell, ObHTableMatchCode &match_code);
private:
ObNegativeTimeRange time_range_;
ObHTableColumnTracker *column_tracker_;
table::hfilter::Filter *hfilter_;
common::ObArenaAllocator allocator_;
ObHTableCellEntity curr_row_; // the first cell of current row
common::ObNewRow curr_ob_row_;
};
class ObHTableRowIterator: public ObTableQueryResultIterator
{
public:
ObHTableRowIterator(const ObTableQuery &query);
virtual ~ObHTableRowIterator();
/// Fetch next row
virtual int get_next_result(ObTableQueryResult *&one_row) override;
int seek(const ObHTableCell &key);
void set_scan_result(common::ObNewRowIterator *scan_result) { child_op_ = scan_result; }
bool has_more_result() const { return has_more_cells_; }
void set_hfilter(table::hfilter::Filter *hfilter);
void set_ttl(int32_t ttl_value);
int add_same_kq_to_res(ObIArray<common::ObNewRow> &same_kq_cells, ObTableQueryResult *&out_result);
ObIArray<common::ObNewRow> &get_same_kq_cells() { return same_kq_cells_; }
private:
int next_cell();
int reverse_next_cell(ObIArray<common::ObNewRow> &same_kq_cells, ObTableQueryResult *&out_result);
int seek_or_skip_to_next_row(const ObHTableCell &cell);
int seek_or_skip_to_next_col(const ObHTableCell &cell);
bool reach_batch_limit() const;
bool reach_size_limit() const;
private:
common::ObNewRowIterator *child_op_;
const table::ObHTableFilter &htable_filter_;
table::hfilter::Filter *hfilter_;
int32_t limit_per_row_per_cf_;
int32_t offset_per_row_per_cf_;
int64_t max_result_size_;
int32_t batch_size_;
int32_t time_to_live_; // Time-to-live of cell contents, in seconds.
table::ObTableQueryResult one_hbase_row_;
ObHTableCellEntity curr_cell_;
common::ObArenaAllocator allocator_; // used for deep copy of curr_cell_
ObHTableColumnTracker *column_tracker_;
ObHTableScanMatcher *matcher_;
ObHTableWildcardColumnTracker column_tracker_wildcard_;
ObHTableExplicitColumnTracker column_tracker_explicit_;
ObHTableScanMatcher matcher_impl_;
common::ObQueryFlag::ScanOrder scan_order_;
ObSEArray<common::ObNewRow, 16> same_kq_cells_;
int32_t cell_count_;
int32_t count_per_row_;
bool has_more_cells_;
};
// entry class
class ObHTableFilterOperator: public ObTableQueryResultIterator
{
public:
ObHTableFilterOperator(const ObTableQuery &query, table::ObTableQueryResult &one_result);
virtual ~ObHTableFilterOperator() {}
/// Fetch next batch result
virtual int get_next_result(ObTableQueryResult *&one_result) override;
virtual bool has_more_result() const override { return row_iterator_.has_more_result(); }
void set_scan_result(common::ObNewRowIterator *scan_result) { row_iterator_.set_scan_result(scan_result); }
void set_ttl(int32_t ttl_value) { row_iterator_.set_ttl(ttl_value); }
// parse the filter string
int parse_filter_string(common::ObArenaAllocator* allocator);
private:
const ObTableQuery &query_;
ObHTableRowIterator row_iterator_;
table::ObTableQueryResult &one_result_;
table::ObHTableFilterParser filter_parser_;
table::hfilter::Filter *hfilter_;
int32_t batch_size_;
int64_t max_result_size_;
bool is_first_result_;
};
} // end namespace table
} // end namespace oceanbase
#endif /* _OB_HTABLE_FILTER_OPERATOR_H */

View File

@ -0,0 +1,229 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX SERVER
#include "ob_htable_filter_parser.h"
#include "htable_filter_lex.hxx"
using namespace oceanbase::table;
using namespace oceanbase::common;
ObHTableFilterParser::ObHTableFilterParser()
:scanner_(nullptr),
error_code_(OB_SUCCESS),
first_column_(0),
last_column_(0),
first_line_(0),
last_line_(0),
allocator_(nullptr),
filter_string_(nullptr),
result_filter_(nullptr)
{
error_msg_[0] = '\0';
}
ObHTableFilterParser::~ObHTableFilterParser()
{
destroy();
}
int ObHTableFilterParser::init(common::ObArenaAllocator* allocator)
{
int ret = OB_SUCCESS;
if (nullptr != scanner_ || nullptr != allocator_) {
ret = OB_INIT_TWICE;
LOG_WARN("scanner already inited", K(ret));
} else {
allocator_ = allocator;
if (OB_FAIL(ob_hfilter_lex_init_extra(this, &scanner_))) {
LOG_WARN("failed to init lex", K(ret));
}
}
return ret;
}
using hfilter::Comparable;
using hfilter::Filter;
void ObHTableFilterParser::destroy()
{
if (nullptr != scanner_) {
ob_hfilter_lex_destroy(scanner_);
scanner_ = nullptr;
}
int64_t N = comparators_.count();
for (int64_t i = 0; i < N; ++i) {
comparators_.at(i)->~Comparable();
}
comparators_.reset();
N = filters_.count();
for (int64_t i = 0; i < N; ++i) {
filters_.at(i)->~Filter();
}
filters_.reset();
}
// @see htable_filter_tab.cxx
extern int ob_hfilter_parse(oceanbase::table::ObHTableFilterParser *parse_ctx);
int ObHTableFilterParser::parse_filter(const ObString &filter_string, hfilter::Filter *&filter)
{
int ret = OB_SUCCESS;
filter = NULL;
filter_string_ = &filter_string;
const char * buf = filter_string.ptr();
int32_t len = filter_string.length();
YY_BUFFER_STATE bp = ob_hfilter__scan_bytes(buf, len, scanner_);
ob_hfilter__switch_to_buffer(bp, scanner_);
ret = ob_hfilter_parse(this); // the bison parser
LOG_DEBUG("parse filter", K(ret), K(filter_string));
if (OB_SUCC(ret)) {
filter = result_filter_;
} else {
if (1 == ret) { // syntax error
if (OB_SUCCESS != error_code_) {
ret = error_code_;
} else {
ret = OB_ERR_PARSER_SYNTAX;
}
}
LOG_WARN("failed to parse filter", K(ret), K_(error_msg), K(filter_string));
}
ob_hfilter__delete_buffer(bp, scanner_);
return ret;
}
const ObString ObHTableFilterParser::BINARY_TYPE = ObString::make_string("binary");
const ObString ObHTableFilterParser::BINARY_PREFIX_TYPE = ObString::make_string("binaryprefix");
const ObString ObHTableFilterParser::REGEX_STRING_TYPE = ObString::make_string("regexstring");
const ObString ObHTableFilterParser::SUB_STRING_TYPE = ObString::make_string("substring");
int ObHTableFilterParser::create_comparator(const SimpleString &bytes, hfilter::Comparable *&comparator)
{
int ret = OB_SUCCESS;
char *p = static_cast<char*>(memchr(bytes.str_, ':', bytes.len_));
if (NULL == p) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("no : found in the comprator", K(ret));
} else {
comparator = NULL;
int64_t len1 = p-bytes.str_;
ObString comparator_type(len1, bytes.str_);
ObString comparator_value(bytes.len_-len1-1, p+1);
if (comparator_type == BINARY_TYPE) {
comparator = OB_NEWx(hfilter::BinaryComparator, allocator_, comparator_value);
} else if (comparator_type == BINARY_PREFIX_TYPE) {
comparator = OB_NEWx(hfilter::BinaryPrefixComparator, allocator_, comparator_value);
} else if (comparator_type == REGEX_STRING_TYPE) {
//comparator = OB_NEWx(hfilter::RegexStringComparator, allocator_, comparator_value);
LOG_WARN("regexstring comparator not supported yet", K(ret));
ret = OB_NOT_SUPPORTED;
} else if (comparator_type == SUB_STRING_TYPE) {
comparator = OB_NEWx(hfilter::SubStringComparator, allocator_, comparator_value);
} else {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid comprator type", K(ret), K(comparator_type));
}
if (OB_SUCC(ret) && NULL == comparator) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
}
if (NULL != comparator) {
if (OB_FAIL(comparators_.push_back(comparator))) {
LOG_WARN("failed to add comparator", K(ret));
comparator->~Comparable();
comparator = NULL;
}
}
}
return ret;
}
int ObHTableFilterParser::create_prefix_comparator(const SimpleString &bytes, hfilter::Comparable *&comparator)
{
int ret = OB_SUCCESS;
ObString comparator_value(bytes.len_, bytes.str_);
comparator = OB_NEWx(hfilter::BinaryPrefixComparator, allocator_, comparator_value);
if (NULL == comparator) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
}
if (NULL != comparator) {
if (OB_FAIL(comparators_.push_back(comparator))) {
LOG_WARN("failed to add comparator", K(ret));
comparator->~Comparable();
comparator = NULL;
}
}
return ret;
}
int ObHTableFilterParser::store_filter(hfilter::Filter *&filter)
{
int ret = OB_SUCCESS;
if (NULL != filter) {
if (OB_FAIL(filters_.push_back(filter))) {
LOG_WARN("failed to add filter", K(ret));
filter->~Filter();
filter = NULL;
}
}
return ret;
}
#include "sql/parser/parse_malloc.h"
void *ObHTableFilterParser::alloc(int64_t size)
{
return parse_malloc(size, allocator_);
}
void *ObHTableFilterParser::realloc(void *ptr, int64_t size)
{
return parse_realloc(ptr, size, allocator_);
}
void ObHTableFilterParser::free(void *ptr)
{
// we don't need to free the memory from arena allocator
UNUSED(ptr);
}
void ob_hfilter_error(YYLTYPE *loc, oceanbase::table::ObHTableFilterParser *p, const char *format_msg, ...)
{
if (OB_LIKELY(NULL != p)) {
va_list ap;
va_start(ap, format_msg);
vsnprintf(p->error_msg_, p->PARSER_ERROR_MSG_SIZE, format_msg, ap);
if (OB_LIKELY(NULL != loc)) {
p->first_column_ = loc->first_column;
p->last_column_ = loc->last_column;
p->first_line_ = loc->first_line;
p->last_line_ = loc->last_line;
}
va_end(ap);
}
}
void *ob_hfilter_alloc(size_t bytes, void* yyscanner)
{
ObHTableFilterParser *p = ob_hfilter_get_extra(yyscanner);
return p->alloc(bytes);
}
void *ob_hfilter_realloc(void *ptr, size_t bytes, void* yyscanner)
{
ObHTableFilterParser *p = ob_hfilter_get_extra(yyscanner);
return p->realloc(ptr, bytes);
}
void ob_hfilter_free(void *ptr, void* yyscanner)
{
ObHTableFilterParser *p = ob_hfilter_get_extra(yyscanner);
p->free(ptr);
}

View File

@ -0,0 +1,95 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef _OB_HTABLE_FILTER_PARSER_H
#define _OB_HTABLE_FILTER_PARSER_H 1
#include "lib/ob_define.h"
#include "lib/string/ob_string.h"
#include "lib/container/ob_se_array.h"
namespace oceanbase
{
namespace common
{
class ObArenaAllocator;
} // end namespace common
namespace table
{
namespace hfilter
{
class Filter;
class Comparable;
}
class ObHTableFilterParser
{
public:
struct SimpleString
{
char *str_;
int64_t len_;
};
public:
static const int64_t PARSER_ERROR_MSG_SIZE = 512;
void *scanner_; // the reentrant lex scanner
int error_code_;
// for yyerror()
int first_column_;
int last_column_;
int first_line_;
int last_line_;
char error_msg_[PARSER_ERROR_MSG_SIZE];
public:
ObHTableFilterParser();
virtual ~ObHTableFilterParser();
int init(common::ObArenaAllocator* allocator);
void destroy();
// parse the filter string
int parse_filter(const common::ObString &filter_string, hfilter::Filter *&filter);
int64_t get_input_len() const { return filter_string_->length(); }
const char *get_input_str() const { return filter_string_->ptr(); }
void set_result_filter(hfilter::Filter *filter) { result_filter_ = filter; }
void *alloc(int64_t size);
void *realloc(void *ptr, int64_t size);
void free(void *ptr);
common::ObArenaAllocator *allocator() { return allocator_; }
int create_comparator(const SimpleString &bytes, hfilter::Comparable *&comparator);
int create_prefix_comparator(const SimpleString &bytes, hfilter::Comparable *&comparator);
int store_filter(hfilter::Filter *&filter);
private:
static const common::ObString BINARY_TYPE;
static const common::ObString BINARY_PREFIX_TYPE;
static const common::ObString REGEX_STRING_TYPE;
static const common::ObString SUB_STRING_TYPE;
private:
common::ObArenaAllocator* allocator_;
common::ObSEArray<hfilter::Comparable*, 8> comparators_;
common::ObSEArray<hfilter::Filter*, 8> filters_;
// the input filter string
const common::ObString *filter_string_;
// parse result
hfilter::Filter *result_filter_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObHTableFilterParser);
};
} // end namespace table
} // end namespace oceanbase
// for yacc/lex error report
class YYLTYPE;
extern void ob_hfilter_error(YYLTYPE *loc, oceanbase::table::ObHTableFilterParser *p, const char *s, ...);
// for flex memory management
extern void *ob_hfilter_alloc(size_t bytes, void* yyscanner);
extern void *ob_hfilter_realloc(void *ptr, size_t bytes, void* yyscanner);
extern void ob_hfilter_free(void *ptr, void* yyscanner);
#endif /* _OB_HTABLE_FILTER_PARSER_H */

View File

@ -0,0 +1,913 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX SERVER
#include "ob_htable_filters.h"
using namespace oceanbase::common;
using namespace oceanbase::table;
using namespace oceanbase::table::hfilter;
Filter::Filter()
:is_reversed_(false)
{
}
Filter::~Filter()
{}
FilterBase::~FilterBase() {}
////////////////////////////////////////////////////////////////
CompareFilter::~CompareFilter()
{}
const char* FilterBase::compare_operator_to_string(CompareOperator cmp_op)
{
const char* op_str = "UNKNOWN";
switch (cmp_op) {
case CompareOperator::EQUAL:
op_str = "EQUAL";
break;
case CompareOperator::GREATER:
op_str = "GREATER";
break;
case CompareOperator::GREATER_OR_EQUAL:
op_str = "GREATER_OR_EQUAL";
break;
case CompareOperator::LESS:
op_str = "LESS";
break;
case CompareOperator::LESS_OR_EQUAL:
op_str = "LESS_OR_EQUAL";
break;
case CompareOperator::NO_OP:
op_str = "NO_OP";
break;
case CompareOperator::NOT_EQUAL:
op_str = "NOT_EQUAL";
break;
default:
break;
}
return op_str;
}
int CompareFilter::check_arguments() const
{
int ret = OB_SUCCESS;
if (NULL != dynamic_cast<RegexStringComparator*>(comparator_)
|| NULL != dynamic_cast<SubStringComparator*>(comparator_)) {
if (CompareOperator::EQUAL != cmp_op_
&& CompareOperator::NOT_EQUAL != cmp_op_) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("regexstring comparator and substring comparator can only be used with EQUAL or NOT_EQUAL", K(ret));
}
}
return ret;
}
// return true indicates it will be filtered
bool CompareFilter::compare(CompareOperator op, int cmp_ret)
{
bool bret = true;
switch (op) {
case CompareOperator::EQUAL:
bret = (0 != cmp_ret);
break;
case CompareOperator::GREATER:
bret = (cmp_ret >= 0);
break;
case CompareOperator::GREATER_OR_EQUAL:
bret = (cmp_ret > 0);
break;
case CompareOperator::LESS:
bret = (cmp_ret <= 0);
break;
case CompareOperator::LESS_OR_EQUAL:
bret = (cmp_ret < 0);
break;
case CompareOperator::NOT_EQUAL:
bret = (cmp_ret == 0);
break;
default:
break;
}
return bret;
}
bool CompareFilter::compare_row(CompareOperator op, Comparable &comparator, const ObHTableCell &cell)
{
bool bret = false;
if (CompareOperator::NO_OP == op) {
bret = true;
} else {
int cmp_ret = comparator.compare_to(cell.get_rowkey());
bret = compare(op, cmp_ret);
}
return bret;
}
bool CompareFilter::compare_qualifier(CompareOperator op, Comparable &comparator, const ObHTableCell &cell)
{
bool bret = false;
if (CompareOperator::NO_OP == op) {
bret = true;
} else {
int cmp_ret = comparator.compare_to(cell.get_qualifier());
bret = compare(op, cmp_ret);
}
return bret;
}
bool CompareFilter::compare_value(CompareOperator op, Comparable &comparator, const ObHTableCell &cell)
{
bool bret = false;
if (CompareOperator::NO_OP == op) {
bret = true;
} else {
int cmp_ret = comparator.compare_to(cell.get_value());
bret = compare(op, cmp_ret);
}
return bret;
}
////////////////////////////////////////////////////////////////
int BinaryComparator::compare_to(const ObString &b)
{
return comparator_value_.compare(b);
}
int BinaryPrefixComparator::compare_to(const ObString &b)
{
int cmp_ret = 0;
if (b.length() <= comparator_value_.length()) {
cmp_ret = comparator_value_.compare(b);
} else {
ObString b_prefix(comparator_value_.length(), b.ptr());
cmp_ret = comparator_value_.compare(b_prefix);
}
return cmp_ret;
}
int RegexStringComparator::compare_to(const ObString &b)
{
// @todo
UNUSED(b);
LOG_WARN("regexstring comparator not supported yet");
return 0;
}
// If value_ is substring of b, return 0; otherwise return 1
int SubStringComparator::compare_to(const ObString &b)
{
int cmp_ret = 0;
char *a_dup = strndupa(comparator_value_.ptr(), comparator_value_.length());
char *b_dup = strndupa(b.ptr(), b.length());
if (NULL == a_dup || NULL == b_dup) {
LOG_WARN("failed to dup string");
} else {
char* p = strcasestr(b_dup, a_dup);
cmp_ret = (NULL == p) ? 1: 0;
}
return cmp_ret;
}
////////////////////////////////////////////////////////////////
RowFilter::~RowFilter()
{}
void RowFilter::reset()
{
filter_out_row_ = false;
}
bool RowFilter::filter_row_key(const ObHTableCell &first_row_cell)
{
filter_out_row_ = compare_row(cmp_op_, *comparator_, first_row_cell);
return filter_out_row_;
}
int RowFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code)
{
int ret = OB_SUCCESS;
UNUSED(cell);
ret_code = (filter_out_row_)?(ReturnCode::NEXT_ROW):(ReturnCode::INCLUDE);
return ret;
}
bool RowFilter::filter_row()
{
return filter_out_row_;
}
////////////////////////////////////////////////////////////////
QualifierFilter::~QualifierFilter()
{}
int QualifierFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code)
{
int ret = OB_SUCCESS;
ret_code = ReturnCode::INCLUDE;
const ObString qualifier = cell.get_qualifier();
if (qualifier.length() > 0) {
if (compare_qualifier(cmp_op_, *comparator_, cell)) {
ret_code = ReturnCode::SKIP;
}
}
return ret;
}
////////////////////////////////////////////////////////////////
ValueFilter::~ValueFilter() {}
int ValueFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code)
{
int ret = OB_SUCCESS;
ret_code = ReturnCode::INCLUDE;
if (compare_value(cmp_op_, *comparator_, cell)) {
ret_code = ReturnCode::SKIP;
}
return ret;
}
////////////////////////////////////////////////////////////////
FilterListBase::~FilterListBase()
{}
int FilterListBase::add_filter(Filter *filter)
{
int ret = OB_SUCCESS;
if (NULL == filter) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("filter is nullptr", K(ret));
} else if (OB_FAIL(filters_.push_back(filter))) {
LOG_WARN("failed to push back", K(ret));
}
return ret;
}
const char* FilterListBase::operator_to_string(Operator op)
{
const char* op_str = "UNKNOWN";
switch(op) {
case Operator::MUST_PASS_ALL:
op_str = "AND";
break;
case Operator::MUST_PASS_ONE:
op_str = "OR";
break;
default:
break;
}
return op_str;
}
void FilterListBase::reset()
{
const int64_t N = filters_.count();
for (int64_t i = 0; i < N; ++i)
{
filters_.at(i)->reset();
} // end for
}
////////////////////////////////////////////////////////////////
FilterListAND::~FilterListAND()
{}
// Maximal Step Rule
Filter::ReturnCode FilterListAND::merge_return_code(ReturnCode rc, ReturnCode local_rc)
{
ReturnCode ret_code = local_rc;
if (rc == ReturnCode::SEEK_NEXT_USING_HINT) {
ret_code = ReturnCode::SEEK_NEXT_USING_HINT;
} else {
switch (local_rc) {
case ReturnCode::SEEK_NEXT_USING_HINT:
ret_code = ReturnCode::SEEK_NEXT_USING_HINT;
break;
case ReturnCode::INCLUDE:
ret_code = rc;
break;
case ReturnCode::INCLUDE_AND_NEXT_COL:
if (rc == ReturnCode::INCLUDE
|| rc == ReturnCode::INCLUDE_AND_NEXT_COL) {
ret_code = ReturnCode::INCLUDE_AND_NEXT_COL;
} else if (rc == ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW) {
ret_code = ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW;
} else if (rc == ReturnCode::SKIP
|| rc == ReturnCode::NEXT_COL) {
ret_code = ReturnCode::NEXT_COL;
} else if (rc == ReturnCode::NEXT_ROW) {
ret_code = ReturnCode::NEXT_ROW;
}
break;
case ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW:
if (rc == ReturnCode::INCLUDE
|| rc == ReturnCode::INCLUDE_AND_NEXT_COL
|| rc == ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW) {
ret_code = ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW;
} else if (rc == ReturnCode::SKIP
|| rc == ReturnCode::NEXT_COL
|| rc == ReturnCode::NEXT_ROW) {
ret_code = ReturnCode::NEXT_ROW;
}
break;
case ReturnCode::SKIP:
if (rc == ReturnCode::INCLUDE
|| rc == ReturnCode::SKIP) {
ret_code = ReturnCode::SKIP;
} else if (rc == ReturnCode::INCLUDE_AND_NEXT_COL
|| rc == ReturnCode::NEXT_COL) {
ret_code = ReturnCode::NEXT_COL;
} else if (rc == ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW
|| rc == ReturnCode::NEXT_ROW) {
ret_code = ReturnCode::NEXT_ROW;
}
break;
case ReturnCode::NEXT_COL:
if (rc == ReturnCode::INCLUDE
|| rc == ReturnCode::INCLUDE_AND_NEXT_COL
|| rc == ReturnCode::SKIP
|| rc == ReturnCode::NEXT_COL) {
ret_code = ReturnCode::NEXT_COL;
} else if (rc == ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW
|| rc == ReturnCode::NEXT_ROW) {
ret_code = ReturnCode::NEXT_ROW;
}
break;
case ReturnCode::NEXT_ROW:
ret_code = ReturnCode::NEXT_ROW;
break;
default:
break;
} // end switch
}
return ret_code;
}
int FilterListAND::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code)
{
int ret = OB_SUCCESS;
if (filters_.empty()) {
ret_code = ReturnCode::INCLUDE;
} else {
ret_code = ReturnCode::INCLUDE;
seek_hint_filters_.reset();
const int64_t N = filters_.count();
for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i)
{
Filter *filter = filters_.at(i);
if (filter->filter_all_remaining()) {
ret_code = ReturnCode::NEXT_ROW;
break;
} else {
ReturnCode local_rc;
if (OB_FAIL(filter->filter_cell(cell, local_rc))) {
LOG_WARN("failed to filter cell", K(ret));
} else {
ret_code = merge_return_code(ret_code, local_rc);
LOG_DEBUG("[yzfdebug] AND filter cell", K(i), K(local_rc), K(ret_code));
if (local_rc == ReturnCode::SEEK_NEXT_USING_HINT) {
if (OB_FAIL(seek_hint_filters_.push_back(filter))) {
LOG_WARN("failed to push back", K(ret));
}
}
}
}
} // end for
if (!seek_hint_filters_.empty()) {
ret_code = ReturnCode::SEEK_NEXT_USING_HINT;
}
}
return ret;
}
void FilterListAND::reset()
{
FilterListBase::reset();
seek_hint_filters_.reset();
}
bool FilterListAND::filter_all_remaining()
{
bool bret = false;
if (filters_.empty()) {
bret = FilterListBase::filter_all_remaining();
} else {
const int64_t N = filters_.count();
for (int64_t i = 0; i < N; ++i)
{
if (filters_.at(i)->filter_all_remaining()) {
bret = true;
break;
}
} // end for
}
return bret;
}
bool FilterListAND::filter_row_key(const ObHTableCell &first_row_cell)
{
bool bret = false;
if (filters_.empty()) {
bret = FilterListBase::filter_row_key(first_row_cell);
} else {
const int64_t N = filters_.count();
for (int64_t i = 0; i < N; ++i)
{
Filter *filter = filters_.at(i);
if (filter->filter_all_remaining() || filter->filter_row_key(first_row_cell)) {
bret = true;
// can not break here
}
} // end for
}
return bret;
}
bool FilterListAND::filter_row()
{
bool bret = false;
if (filters_.empty()) {
bret = FilterListBase::filter_row();
} else {
const int64_t N = filters_.count();
for (int64_t i = 0; i < N; ++i)
{
Filter *filter = filters_.at(i);
if (filter->filter_row()) {
bret = true;
break;
}
} // end for
}
return bret;
}
////////////////////////////////////////////////////////////////
FilterListOR::~FilterListOR()
{}
void FilterListOR::reset()
{
FilterListBase::reset();
}
bool FilterListOR::filter_all_remaining()
{
bool bret = true;
if (filters_.empty()) {
bret = FilterListBase::filter_all_remaining();
} else {
const int64_t N = filters_.count();
for (int64_t i = 0; i < N; ++i)
{
if (!filters_.at(i)->filter_all_remaining()) {
bret = false;
break;
}
} // end for
}
return bret;
}
bool FilterListOR::filter_row_key(const ObHTableCell &first_row_cell)
{
bool bret = true;
if (filters_.empty()) {
bret = FilterListBase::filter_row_key(first_row_cell);
} else {
const int64_t N = filters_.count();
for (int64_t i = 0; i < N; ++i)
{
Filter *filter = filters_.at(i);
if (!filter->filter_all_remaining() && !filter->filter_row_key(first_row_cell)) {
bret = false;
// can not break here
}
} // end for
}
return bret;
}
// Minimal Step Rule
Filter::ReturnCode FilterListOR::merge_return_code(ReturnCode rc, ReturnCode local_rc)
{
ReturnCode ret_code = local_rc;
switch (local_rc) {
case ReturnCode::INCLUDE:
ret_code = ReturnCode::INCLUDE;
break;
case ReturnCode::INCLUDE_AND_NEXT_COL:
if (ReturnCode::INCLUDE == rc
|| ReturnCode::SKIP == rc
|| ReturnCode::SEEK_NEXT_USING_HINT == rc) {
ret_code = ReturnCode::INCLUDE;
} else if (ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW == rc
|| ReturnCode::INCLUDE_AND_NEXT_COL == rc
|| ReturnCode::NEXT_COL == rc
|| ReturnCode::NEXT_ROW == rc) {
ret_code = ReturnCode::INCLUDE_AND_NEXT_COL;
}
break;
case ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW:
if (ReturnCode::INCLUDE == rc
|| ReturnCode::SKIP == rc
|| ReturnCode::SEEK_NEXT_USING_HINT == rc) {
ret_code = ReturnCode::INCLUDE;
} else if (ReturnCode::INCLUDE_AND_NEXT_COL == rc
|| ReturnCode::NEXT_COL == rc) {
ret_code = ReturnCode::INCLUDE_AND_NEXT_COL;
} else if (ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW == rc
|| ReturnCode::NEXT_ROW == rc) {
ret_code = ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW;
}
break;
case ReturnCode::SKIP:
if (ReturnCode::INCLUDE == rc
|| ReturnCode::INCLUDE_AND_NEXT_COL == rc
|| ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW == rc) {
ret_code = ReturnCode::INCLUDE;
} else {
ret_code = ReturnCode::SKIP;
}
break;
case ReturnCode::NEXT_COL:
{
switch (rc) {
case ReturnCode::INCLUDE:
ret_code = ReturnCode::INCLUDE;
break;
case ReturnCode::NEXT_COL:
case ReturnCode::NEXT_ROW:
ret_code = ReturnCode::NEXT_COL;
break;
case ReturnCode::INCLUDE_AND_NEXT_COL:
case ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW:
ret_code = ReturnCode::INCLUDE_AND_NEXT_COL;
break;
case ReturnCode::SKIP:
case ReturnCode::SEEK_NEXT_USING_HINT:
ret_code = ReturnCode::SKIP;
break;
default:
LOG_ERROR("BUG");
break;
}
}
break;
case ReturnCode::NEXT_ROW:
{
switch (rc) {
case ReturnCode::INCLUDE:
ret_code = ReturnCode::INCLUDE;
break;
case ReturnCode::NEXT_COL:
ret_code = ReturnCode::NEXT_COL;
break;
case ReturnCode::NEXT_ROW:
ret_code = ReturnCode::NEXT_ROW;
break;
case ReturnCode::INCLUDE_AND_NEXT_COL:
ret_code = ReturnCode::INCLUDE_AND_NEXT_COL;
break;
case ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW:
ret_code = ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW;
break;
case ReturnCode::SKIP:
case ReturnCode::SEEK_NEXT_USING_HINT:
ret_code = ReturnCode::SKIP;
break;
default:
LOG_ERROR("BUG");
break;
}
}
break;
case ReturnCode::SEEK_NEXT_USING_HINT:
{
switch (rc) {
case ReturnCode::INCLUDE:
case ReturnCode::INCLUDE_AND_NEXT_COL:
case ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW:
ret_code = ReturnCode::INCLUDE;
break;
case ReturnCode::SKIP:
case ReturnCode::NEXT_COL:
case ReturnCode::NEXT_ROW:
ret_code = ReturnCode::SKIP;
break;
case ReturnCode::SEEK_NEXT_USING_HINT:
ret_code = ReturnCode::SEEK_NEXT_USING_HINT;
break;
default:
LOG_ERROR("BUG", K(rc));
break;
}
}
break;
default:
LOG_ERROR("BUG", K(local_rc));
break;
} // end switch
return ret_code;
}
int FilterListOR::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code)
{
int ret = OB_SUCCESS;
if (filters_.empty()) {
ret_code = ReturnCode::INCLUDE;
} else {
bool every_filter_return_hint = true;
ret_code = ReturnCode::SKIP; // Each sub-filter in filter list got true for filterAllRemaining().
const int64_t N = filters_.count();
for (int64_t i = 0; i < N; ++i)
{
Filter *filter = filters_.at(i);
if (filter->filter_all_remaining()) {
continue;
} else {
ReturnCode local_rc;
if (OB_FAIL(filter->filter_cell(cell, local_rc))) {
LOG_WARN("failed to filter cell", K(ret));
} else {
if (ReturnCode::SEEK_NEXT_USING_HINT != local_rc) {
every_filter_return_hint = false;
}
ret_code = merge_return_code(ret_code, local_rc);
LOG_DEBUG("[yzfdebug] OR filter cell", K(i), K(local_rc), K(ret_code));
}
}
} // end for
if (every_filter_return_hint) {
ret_code = ReturnCode::SEEK_NEXT_USING_HINT;
}
}
return ret;
}
bool FilterListOR::filter_row()
{
bool bret = true;
if (filters_.empty()) {
bret = FilterListBase::filter_row();
} else {
const int64_t N = filters_.count();
for (int64_t i = 0; i < N; ++i)
{
Filter *filter = filters_.at(i);
if (!filter->filter_row()) {
bret = false;
break;
}
} // end for
}
return bret;
}
////////////////////////////////////////////////////////////////
SkipFilter::~SkipFilter() {}
void SkipFilter::reset()
{
if (NULL != filter_) {
filter_->reset();
}
filter_row_ = false;
}
bool SkipFilter::filter_row_key(const ObHTableCell &first_row_cell)
{
UNUSED(first_row_cell);
return false;
}
// A wrapper filter that filters an entire row if any of the Cell checks do not pass.
int SkipFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code)
{
int ret = OB_SUCCESS;
if (OB_FAIL(filter_->filter_cell(cell, ret_code))) {
} else {
filter_row_ = filter_row_ || (ReturnCode::INCLUDE != ret_code);
}
return ret;
}
bool SkipFilter::filter_row()
{
return filter_row_;
}
int SkipFilter::transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell)
{
return filter_->transform_cell(cell, new_cell);
}
////////////////////////////////////////////////////////////////
WhileMatchFilter::~WhileMatchFilter() {}
void WhileMatchFilter::reset()
{
if (NULL != filter_) {
filter_->reset();
}
}
bool WhileMatchFilter::filter_all_remaining()
{
return filter_all_remaining_ || filter_->filter_all_remaining();
}
bool WhileMatchFilter::filter_row_key(const ObHTableCell &first_row_cell)
{
bool bret = true;
if (filter_all_remaining()) {
bret = true;
} else {
bret = filter_->filter_row_key(first_row_cell);
filter_all_remaining_ = filter_all_remaining_ || bret;
}
return bret;
}
int WhileMatchFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code)
{
int ret = OB_SUCCESS;
if (OB_FAIL(filter_->filter_cell(cell, ret_code))) {
} else {
filter_all_remaining_ = filter_all_remaining_ || (ReturnCode::INCLUDE != ret_code);
}
return ret;
}
int WhileMatchFilter::transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell)
{
return filter_->transform_cell(cell, new_cell);
}
bool WhileMatchFilter::filter_row()
{
bool bret = filter_->filter_row();
filter_all_remaining_ = filter_all_remaining_ || bret;
return bret;
}
////////////////////////////////////////////////////////////////
SingleColumnValueFilter::~SingleColumnValueFilter()
{}
void SingleColumnValueFilter::reset()
{
LOG_DEBUG("[yzfdebug] reset SingleColumnValueFilter");
found_column_ = false;
matched_column_ = false;
}
int SingleColumnValueFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code)
{
int ret = OB_SUCCESS;
if (matched_column_) {
// already found and matched the single column
ret_code = ReturnCode::INCLUDE;
LOG_DEBUG("[yzfdebug] already matched column", K(ret_code));
} else if (latest_version_only_ && found_column_) {
// found but not matched the column
ret_code = ReturnCode::NEXT_ROW;
LOG_DEBUG("[yzfdebug] latest verion only but not matched", K(ret_code));
} else if (!match_column(cell)) {
ret_code = ReturnCode::INCLUDE;
LOG_DEBUG("[yzfdebug] not found column yet", K(ret_code));
} else {
found_column_ = true;
LOG_DEBUG("[yzfdebug] found column", K_(found_column));
if (filter_column_value(cell)) {
ret_code = (latest_version_only_) ? (ReturnCode::NEXT_ROW) : (ReturnCode::INCLUDE);
LOG_DEBUG("[yzfdebug] found column but value not match", K_(latest_version_only), K(ret_code));
} else {
matched_column_ = true;
ret_code = ReturnCode::INCLUDE;
LOG_DEBUG("[yzfdebug] found column and match", K(ret_code));
}
}
return ret;
}
bool SingleColumnValueFilter::match_column(const ObHTableCell &cell)
{
return qualifier_ == cell.get_qualifier();
}
bool SingleColumnValueFilter::filter_column_value(const ObHTableCell &cell)
{
int cmp_ret = comparator_->compare_to(cell.get_value());
return CompareFilter::compare(cmp_op_, cmp_ret);
}
bool SingleColumnValueFilter::filter_row()
{
LOG_DEBUG("[yzfdebug] filter row", K_(found_column), K_(matched_column), K_(filter_if_missing));
return found_column_ ? (!matched_column_) : (filter_if_missing_);
}
////////////////////////////////////////////////////////////////
void ColumnCountGetFilter::reset()
{
count_ = 0;
}
bool ColumnCountGetFilter::filter_row_key(const ObHTableCell &first_row_cell)
{
UNUSED(first_row_cell);
return filter_all_remaining();
}
bool ColumnCountGetFilter::filter_all_remaining()
{
return count_ > limit_;
}
int ColumnCountGetFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code)
{
int ret = OB_SUCCESS;
UNUSED(cell);
++count_;
if (filter_all_remaining()) {
ret_code = ReturnCode::NEXT_COL;
} else {
ret_code = ReturnCode::INCLUDE_AND_NEXT_COL;
}
return ret;
}
////////////////////////////////////////////////////////////////
CheckAndMutateFilter::~CheckAndMutateFilter()
{}
void CheckAndMutateFilter::reset()
{
LOG_DEBUG("[yzfdebug] reset CheckAndMutateFilter");
found_column_ = false;
matched_column_ = false;
}
int CheckAndMutateFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code)
{
int ret = OB_SUCCESS;
if (matched_column_) {
// already found and matched the single column
ret_code = ReturnCode::INCLUDE;
LOG_DEBUG("[yzfdebug] already matched column", K(ret_code));
} else if (found_column_) { // latest_version_only_ == true
// found but not matched the column
if (value_is_null_) {
ret_code = ReturnCode::INCLUDE;
} else {
ret_code = ReturnCode::NEXT_ROW;
}
LOG_DEBUG("[yzfdebug] latest verion only but not matched", K(ret_code));
} else if (!match_column(cell)) {
ret_code = ReturnCode::INCLUDE;
LOG_DEBUG("[yzfdebug] not found column yet", K(ret_code));
} else {
found_column_ = true;
LOG_DEBUG("[yzfdebug] found column", K_(found_column));
if (value_is_null_) {
ret_code = ReturnCode::NEXT_ROW;
} else {
if (filter_column_value(cell)) {
ret_code = ReturnCode::NEXT_ROW;
LOG_DEBUG("[yzfdebug] found column but value not match", K(ret_code));
} else {
matched_column_ = true;
ret_code = ReturnCode::INCLUDE;
LOG_DEBUG("[yzfdebug] found column and match", K(ret_code));
}
}
}
return ret;
}
bool CheckAndMutateFilter::match_column(const ObHTableCell &cell)
{
return qualifier_ == cell.get_qualifier();
}
bool CheckAndMutateFilter::filter_column_value(const ObHTableCell &cell)
{
int cmp_ret = comparator_->compare_to(cell.get_value());
return CompareFilter::compare(cmp_op_, cmp_ret);
}
bool CheckAndMutateFilter::filter_row()
{
LOG_DEBUG("[yzfdebug] filter row", K_(found_column), K_(matched_column), K_(value_is_null));
bool bret = true;
if (value_is_null_) {
bret = found_column_;
} else {
bret = found_column_ ? (!matched_column_) : (false/*filter_if_missing*/);
}
return bret;
}

View File

@ -0,0 +1,492 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef _OB_HTABLE_FILTERS_H
#define _OB_HTABLE_FILTERS_H 1
#include "ob_htable_utils.h"
#include "share/table/ob_table_rpc_struct.h"
namespace oceanbase
{
namespace table
{
/// hbase filters
/// @see https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/Filter.html
namespace hfilter
{
typedef table::ObTableQueryResult RowCells;
/** Interface Filter
* Interface for row and column filters directly applied within the regionserver. A filter can expect the following call sequence:
* + reset() : reset the filter state before filtering a new row.
* + filterAllRemaining(): true means row scan is over; false means keep going.
* + filterRowKey(Cell): true means drop this row; false means include.
* + filterCell(Cell): decides whether to include or exclude this Cell. See Filter.ReturnCode.
* + transformCell(Cell): if the Cell is included, let the filter transform the Cell.
* + filterRowCells(List): allows direct modification of the final list to be submitted
* + filterRow(): last chance to drop entire row based on the sequence of filter calls. Eg: filter a row if it doesn't contain a specified column.
*/
class Filter
{
public:
enum class ReturnCode
{
INCLUDE = 0,
INCLUDE_AND_NEXT_COL = 1,
INCLUDE_AND_SEEK_NEXT_ROW = 2,
SKIP = 3,
NEXT_COL = 4,
NEXT_ROW = 5,
SEEK_NEXT_USING_HINT = 6
};
public:
Filter();
virtual ~Filter();
/// Reset the state of the filter between rows.
virtual void reset() = 0;
/// If this returns true, the scan will terminate.
virtual bool filter_all_remaining() = 0;
/// Filters a row based on the row key.
virtual bool filter_row_key(const ObHTableCell &first_row_cell) = 0;
/// A way to filter based on the column family, column qualifier and/or the column value.
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) = 0;
/// Give the filter a chance to transform the passed KeyValue.
virtual int transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell) = 0;
/// Chance to alter the list of Cells to be submitted.
virtual int filter_row_cells(const RowCells &cells) = 0;
/// Last chance to veto row based on previous filterCell(Cell) calls.
virtual bool filter_row() = 0;
/// Primarily used to check for conflicts with scans(such as scans that do not read a full row at a time).
virtual bool has_filter_row() = 0;
void set_reversed(bool reversed) { is_reversed_ = reversed; }
bool is_reversed() const { return is_reversed_; }
VIRTUAL_TO_STRING_KV("filter", "Filter");
protected:
bool is_reversed_;
private:
DISALLOW_COPY_AND_ASSIGN(Filter);
};
enum class CompareOperator
{
EQUAL, GREATER, GREATER_OR_EQUAL, LESS, LESS_OR_EQUAL, NO_OP, NOT_EQUAL
};
class FilterBase: public Filter
{
public:
FilterBase() {}
virtual ~FilterBase();
virtual void reset() override {}
virtual bool filter_all_remaining() override { return false; }
virtual bool filter_row_key(const ObHTableCell &first_row_cell) override
{ UNUSED(first_row_cell); if (filter_all_remaining()) return true; else return false; }
virtual int transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell) override
{ new_cell = &cell; return common::OB_SUCCESS; }
virtual int filter_row_cells(const RowCells &cells) override
{ UNUSED(cells); return common::OB_SUCCESS; }
virtual bool filter_row() override { return false; }
virtual bool has_filter_row() override { return false; }
static const char* compare_operator_to_string(CompareOperator cmp_op);
private:
DISALLOW_COPY_AND_ASSIGN(FilterBase);
};
class Comparable
{
public:
Comparable(const ObString &comparator_value)
:comparator_value_(comparator_value)
{}
virtual ~Comparable() {}
virtual int compare_to(const ObString &b) = 0;
VIRTUAL_TO_STRING_KV("comprable", "Comprable");
protected:
ObString comparator_value_;
private:
DISALLOW_COPY_AND_ASSIGN(Comparable);
};
class BinaryComparator: public Comparable
{
public:
BinaryComparator(const ObString &comparator_value)
:Comparable(comparator_value)
{}
virtual ~BinaryComparator() {}
virtual int compare_to(const ObString &b) override;
TO_STRING_KV("comparable", "BinaryComparator");
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(BinaryComparator);
};
class BinaryPrefixComparator: public Comparable
{
public:
BinaryPrefixComparator(const ObString &comparator_value)
:Comparable(comparator_value)
{}
virtual ~BinaryPrefixComparator() {}
virtual int compare_to(const ObString &b) override;
TO_STRING_KV("comparable", "BinaryPrefixComparator");
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(BinaryPrefixComparator);
};
class RegexStringComparator: public Comparable
{
public:
RegexStringComparator(const ObString &comparator_value)
:Comparable(comparator_value)
{}
virtual ~RegexStringComparator() {}
virtual int compare_to(const ObString &b) override;
TO_STRING_KV("comparable", "RegexStringComparator");
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(RegexStringComparator);
};
class SubStringComparator: public Comparable
{
public:
SubStringComparator(const ObString &comparator_value)
:Comparable(comparator_value)
{}
virtual ~SubStringComparator() {}
virtual int compare_to(const ObString &b) override;
TO_STRING_KV("comparable", "SubStringComparator");
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(SubStringComparator);
};
class CompareFilter: public FilterBase
{
public:
CompareFilter(CompareOperator cmp_op, Comparable *comparator)
:cmp_op_(cmp_op),
comparator_(comparator)
{}
virtual ~CompareFilter();
int check_arguments() const;
static bool compare(CompareOperator op, int cmp_ret);
protected:
bool compare_row(CompareOperator op, Comparable &comparator, const ObHTableCell &cell);
bool compare_qualifier(CompareOperator op, Comparable &comparator, const ObHTableCell &cell);
bool compare_value(CompareOperator op, Comparable &comparator, const ObHTableCell &cell);
protected:
CompareOperator cmp_op_;
Comparable *comparator_;
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(CompareFilter);
};
/// This filter is used to filter based on the key.
class RowFilter: public CompareFilter
{
public:
RowFilter(CompareOperator cmp_op, Comparable *comparator)
:CompareFilter(cmp_op, comparator),
filter_out_row_(false)
{}
virtual ~RowFilter();
virtual void reset() override;
virtual bool filter_row_key(const ObHTableCell &first_row_cell) override;
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override;
virtual bool filter_row() override;
TO_STRING_KV("filter", "RowFilter",
"cmp_op", compare_operator_to_string(cmp_op_),
"comparator", comparator_);
private:
bool filter_out_row_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(RowFilter);
};
/// This filter is used to filter based on the key.
class QualifierFilter: public CompareFilter
{
public:
QualifierFilter(CompareOperator cmp_op, Comparable *comparator)
:CompareFilter(cmp_op, comparator)
{}
virtual ~QualifierFilter();
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override;
TO_STRING_KV("filter", "QualifierFilter",
"cmp_op", compare_operator_to_string(cmp_op_),
"comparator", comparator_);
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(QualifierFilter);
};
/// This filter is used to filter based on column value.
class ValueFilter: public CompareFilter
{
public:
ValueFilter(CompareOperator cmp_op, Comparable *comparator)
:CompareFilter(cmp_op, comparator)
{}
virtual ~ValueFilter();
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override;
TO_STRING_KV("filter", "ValueFilter",
"cmp_op", compare_operator_to_string(cmp_op_),
"comparator", comparator_);
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ValueFilter);
};
/// represents an ordered List of Filters which will be evaluated with a specified boolean operator
/// FilterList.Operator.MUST_PASS_ALL (AND) or FilterList.Operator.MUST_PASS_ONE (OR).
class FilterListBase: public FilterBase
{
public:
enum class Operator
{ MUST_PASS_ALL/*AND*/, MUST_PASS_ONE/*OR*/ };
public:
FilterListBase(Operator op)
:op_(op)
{}
virtual ~FilterListBase();
int add_filter(Filter *filter);
Operator get_operator() const { return op_; }
virtual void reset() override;
TO_STRING_KV("filter", "FilterList",
"op", operator_to_string(op_),
"filters", filters_);
static const char* operator_to_string(Operator op);
protected:
Operator op_;
ObSEArray<Filter*, 8> filters_;
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(FilterListBase);
};
class FilterListAND: public FilterListBase
{
public:
FilterListAND(Operator op)
:FilterListBase(op)
{}
virtual ~FilterListAND();
virtual void reset() override;
virtual bool filter_all_remaining() override;
virtual bool filter_row_key(const ObHTableCell &first_row_cell) override;
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override;
virtual bool filter_row() override;
private:
static ReturnCode merge_return_code(ReturnCode rc, ReturnCode local_rc);
ObSEArray<Filter*, 8> seek_hint_filters_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(FilterListAND);
};
class FilterListOR: public FilterListBase
{
public:
FilterListOR(Operator op)
:FilterListBase(op)
{}
virtual ~FilterListOR();
virtual void reset() override;
virtual bool filter_all_remaining() override;
virtual bool filter_row_key(const ObHTableCell &first_row_cell) override;
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override;
virtual bool filter_row() override;
private:
static ReturnCode merge_return_code(ReturnCode rc, ReturnCode local_rc);
// disallow copy
DISALLOW_COPY_AND_ASSIGN(FilterListOR);
};
/// A wrapper filter that filters an entire row if any of the Cell checks do not pass.
class SkipFilter: public FilterBase
{
public:
SkipFilter(Filter *filter)
:filter_(filter),
filter_row_(false)
{}
virtual ~SkipFilter();
virtual void reset() override;
virtual bool filter_row_key(const ObHTableCell &first_row_cell) override;
virtual bool filter_row() override;
virtual bool has_filter_row() override { return true; }
virtual int transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell) override;
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override;
TO_STRING_KV("filter", "SkipFilter",
"sub_filter", filter_);
private:
Filter *filter_;
bool filter_row_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(SkipFilter);
};
/// A wrapper filter that returns true from filterAllRemaining() as soon as the wrapped filters
/// Filter.filterRowKey(), Filter.filterCell(), Filter.filterRow() or Filter.filterAllRemaining() methods returns true.
class WhileMatchFilter: public FilterBase
{
public:
WhileMatchFilter(Filter *filter)
:filter_(filter),
filter_all_remaining_(false)
{}
virtual ~WhileMatchFilter();
virtual void reset() override;
virtual bool filter_all_remaining() override;
virtual bool filter_row_key(const ObHTableCell &first_row_cell) override;
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override;
virtual int transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell) override;
virtual bool filter_row() override;
virtual bool has_filter_row() override { return true; }
TO_STRING_KV("filter", "WhileMatchFilter",
"sub_filter", filter_);
private:
Filter *filter_;
bool filter_all_remaining_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(WhileMatchFilter);
};
class SingleColumnValueFilter: public FilterBase
{
public:
SingleColumnValueFilter(const ObString &family, const ObString &qualifier, CompareOperator cmp_op, Comparable *comparator)
:family_(family),
qualifier_(qualifier),
cmp_op_(cmp_op),
comparator_(comparator),
filter_if_missing_(false),
latest_version_only_(true),
found_column_(false),
matched_column_(false)
{}
virtual ~SingleColumnValueFilter();
void set_filter_if_missing(bool v) { filter_if_missing_ = v; }
void set_latest_version_only(bool v) { latest_version_only_ = v; }
virtual void reset() override;
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override;
virtual bool filter_row() override;
virtual bool has_filter_row() override { return true; }
TO_STRING_KV("filter", "SingleColumnValueFilter",
K_(family),
K_(qualifier),
"cmp_op", compare_operator_to_string(cmp_op_),
K_(comparator),
K_(filter_if_missing),
K_(latest_version_only));
private:
bool filter_column_value(const ObHTableCell &cell);
bool match_column(const ObHTableCell &cell);
private:
ObString family_;
ObString qualifier_;
CompareOperator cmp_op_;
Comparable *comparator_;
bool filter_if_missing_; // default: false
bool latest_version_only_; // default: true
// state
bool found_column_;
bool matched_column_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(SingleColumnValueFilter);
};
/// Simple filter that returns first N columns on row only.
class ColumnCountGetFilter: public FilterBase
{
public:
ColumnCountGetFilter(int64_t limit)
:limit_(limit),
count_(0)
{}
virtual ~ColumnCountGetFilter() {}
virtual void reset() override;
virtual bool filter_row_key(const ObHTableCell &first_row_cell) override;
virtual bool filter_all_remaining() override;
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override;
TO_STRING_KV("filter", "ColumnCountGetFilter",
K_(limit));
private:
int64_t limit_;
int64_t count_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ColumnCountGetFilter);
};
/// CheckAndMutateFilter is used to implement the check logic of CheckAndMutate
/// @see https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html#checkAndMutate-byte:A-byte:A-
class CheckAndMutateFilter: public FilterBase
{
public:
CheckAndMutateFilter(const ObString &family, const ObString &qualifier, CompareOperator cmp_op,
Comparable *comparator, bool value_is_null)
:family_(family),
qualifier_(qualifier),
cmp_op_(cmp_op),
comparator_(comparator),
value_is_null_(value_is_null),
found_column_(false),
matched_column_(false)
{}
virtual ~CheckAndMutateFilter();
virtual void reset() override;
virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override;
virtual bool filter_row() override;
virtual bool has_filter_row() override { return true; }
TO_STRING_KV("filter", "CheckAndMutateFilter",
K_(family),
K_(qualifier),
"cmp_op", compare_operator_to_string(cmp_op_),
K_(comparator),
K_(value_is_null));
private:
bool filter_column_value(const ObHTableCell &cell);
bool match_column(const ObHTableCell &cell);
private:
ObString family_;
ObString qualifier_;
CompareOperator cmp_op_;
Comparable *comparator_;
// If the passed value is null, the check is for the lack of column (ie: non-existence)
bool value_is_null_; // default: false
// state
bool found_column_;
bool matched_column_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(CheckAndMutateFilter);
};
} // end namespace hfilter
} // end namespace table
} // end namespace oceanbase
#endif /* _OB_HTABLE_FILTERS_H */

View File

@ -0,0 +1,312 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX SERVER
#include "ob_htable_utils.h"
#include <endian.h> // be64toh
using namespace oceanbase::common;
using namespace oceanbase::table;
ObHTableCellEntity::ObHTableCellEntity(common::ObNewRow *ob_row)
:ob_row_(ob_row)
{}
ObHTableCellEntity::ObHTableCellEntity()
:ob_row_(NULL)
{}
ObHTableCellEntity::~ObHTableCellEntity()
{}
ObString ObHTableCellEntity::get_rowkey() const
{
return ob_row_->get_cell(ObHTableConstants::COL_IDX_K).get_varchar();
}
ObString ObHTableCellEntity::get_qualifier() const
{
return ob_row_->get_cell(ObHTableConstants::COL_IDX_Q).get_varchar();
}
int64_t ObHTableCellEntity::get_timestamp() const
{
return ob_row_->get_cell(ObHTableConstants::COL_IDX_T).get_int();
}
ObString ObHTableCellEntity::get_value() const
{
return ob_row_->get_cell(ObHTableConstants::COL_IDX_V).get_varchar();
}
////////////////////////////////////////////////////////////////
ObString ObHTableCellEntity2::get_rowkey() const
{
ObString rowkey_str;
int ret = OB_SUCCESS;
ObObj val;
if (OB_FAIL(entity_->get_property(ObHTableConstants::ROWKEY_CNAME_STR, val))) {
LOG_WARN("failed to get property K", K(ret));
} else {
rowkey_str = val.get_varchar();
}
return rowkey_str;
}
ObString ObHTableCellEntity2::get_qualifier() const
{
ObString rowkey_str;
int ret = OB_SUCCESS;
ObObj val;
if (OB_FAIL(entity_->get_property(ObHTableConstants::CQ_CNAME_STR, val))) {
LOG_WARN("failed to get property K", K(ret));
} else {
rowkey_str = val.get_varchar();
}
return rowkey_str;
}
int64_t ObHTableCellEntity2::get_timestamp() const
{
int64_t ts = -1;
int ret = OB_SUCCESS;
ObObj val;
if (OB_FAIL(entity_->get_property(ObHTableConstants::VERSION_CNAME_STR, val))) {
LOG_WARN("failed to get property K", K(ret));
} else {
ts = val.get_int();
}
return ts;
}
ObString ObHTableCellEntity2::get_value() const
{
ObString rowkey_str;
int ret = OB_SUCCESS;
ObObj val;
if (OB_FAIL(entity_->get_property(ObHTableConstants::VALUE_CNAME_STR, val))) {
LOG_WARN("failed to get property K", K(ret));
} else {
rowkey_str = val.get_varchar();
}
return rowkey_str;
}
////////////////////////////////////////////////////////////////
ObString ObHTableCellEntity3::get_rowkey() const
{
int ret = OB_SUCCESS;
last_get_is_null_ = false;
ObObj obj;
ObString val;
if (OB_FAIL(entity_->get_rowkey_value(ObHTableConstants::COL_IDX_K, obj))) {
LOG_WARN("failed to get K from entity", K(ret), K_(entity));
} else if (obj.is_null()) {
last_get_is_null_ = true;
} else {
val = obj.get_varchar();
}
return val;
}
ObString ObHTableCellEntity3::get_qualifier() const
{
int ret = OB_SUCCESS;
last_get_is_null_ = false;
ObObj obj;
ObString val;
if (OB_FAIL(entity_->get_rowkey_value(ObHTableConstants::COL_IDX_Q, obj))) {
LOG_WARN("failed to get T from entity", K(ret), K_(entity));
} else if (obj.is_null()) {
last_get_is_null_ = true;
} else {
val = obj.get_varchar();
}
return val;
}
int64_t ObHTableCellEntity3::get_timestamp() const
{
int ret = OB_SUCCESS;
last_get_is_null_ = false;
ObObj obj;
int64_t val = 0;
if (OB_FAIL(entity_->get_rowkey_value(ObHTableConstants::COL_IDX_T, obj))) {
LOG_WARN("failed to get T from entity", K(ret), K_(entity));
} else if (obj.is_null()) {
last_get_is_null_ = true;
} else if (OB_FAIL(obj.get_int(val))) {
LOG_WARN("invalid obj type for T", K(ret), K(obj));
last_get_is_null_ = true;
}
return val;
}
ObString ObHTableCellEntity3::get_value() const
{
int ret = OB_SUCCESS;
last_get_is_null_ = false;
ObObj obj;
ObString str;
if (OB_FAIL(entity_->get_property(ObHTableConstants::VALUE_CNAME_STR, obj))) {
LOG_WARN("failed to get property V", K(ret), K_(entity));
} else if (obj.is_null()) {
last_get_is_null_ = true;
} else if (!obj.is_string_type()) {
LOG_WARN("invalid obj type", K(ret), K(obj));
last_get_is_null_ = true;
} else {
str = obj.get_varchar();
}
return str;
}
////////////////////////////////////////////////////////////////
int ObHTableUtils::create_last_cell_on_row_col(common::ObArenaAllocator &allocator,
const ObHTableCell &cell, ObHTableCell *&new_cell)
{
int ret = OB_SUCCESS;
ObString rowkey_clone;
ObString qualifier_clone;
if (OB_FAIL(ob_write_string(allocator, cell.get_rowkey(), rowkey_clone))) {
LOG_WARN("failed to clone rowkey", K(ret));
} else if (OB_FAIL(ob_write_string(allocator, cell.get_qualifier(), qualifier_clone))) {
LOG_WARN("failed to clone qualifier", K(ret));
} else {
new_cell = OB_NEWx(ObHTableLastOnRowColCell, (&allocator), rowkey_clone, qualifier_clone);
if (NULL == new_cell) {
LOG_WARN("no memory", K(ret));
ret = OB_ALLOCATE_MEMORY_FAILED;
}
}
return ret;
}
int ObHTableUtils::create_first_cell_on_row_col(common::ObArenaAllocator &allocator,
const ObHTableCell &cell,
const common::ObString &qualifier,
ObHTableCell *&new_cell)
{
int ret = OB_SUCCESS;
ObString rowkey_clone;
ObString qualifier_clone;
if (OB_FAIL(ob_write_string(allocator, cell.get_rowkey(), rowkey_clone))) {
LOG_WARN("failed to clone rowkey", K(ret));
} else if (OB_FAIL(ob_write_string(allocator, qualifier, qualifier_clone))) {
LOG_WARN("failed to clone qualifier", K(ret));
} else {
new_cell = OB_NEWx(ObHTableFirstOnRowColCell, (&allocator), rowkey_clone, qualifier_clone);
if (NULL == new_cell) {
LOG_WARN("no memory", K(ret));
ret = OB_ALLOCATE_MEMORY_FAILED;
}
}
return ret;
}
int ObHTableUtils::create_last_cell_on_row(common::ObArenaAllocator &allocator,
const ObHTableCell &cell, ObHTableCell *&new_cell)
{
int ret = OB_SUCCESS;
ObString rowkey_clone;
if (OB_FAIL(ob_write_string(allocator, cell.get_rowkey(), rowkey_clone))) {
LOG_WARN("failed to clone rowkey", K(ret));
} else {
new_cell = OB_NEWx(ObHTableLastOnRowCell, (&allocator), rowkey_clone);
if (NULL == new_cell) {
LOG_WARN("no memory", K(ret));
ret = OB_ALLOCATE_MEMORY_FAILED;
}
}
return ret;
}
int ObHTableUtils::compare_cell(const ObHTableCell &cell1, const ObHTableCell &cell2, common::ObQueryFlag::ScanOrder &scan_order)
{
// compare rowkey
int cmp_ret;
if (common::ObQueryFlag::Reverse == scan_order) {
cmp_ret = cell2.get_rowkey().compare(cell1.get_rowkey());
} else {
cmp_ret = cell1.get_rowkey().compare(cell2.get_rowkey());
}
if (0 == cmp_ret) {
// the same rowkey
if (ObHTableCell::Type::LAST_ON_ROW == cell1.get_type()) {
// cell1 is last cell on row
cmp_ret = 1;
} else if (ObHTableCell::Type::LAST_ON_ROW == cell2.get_type()) {
// cell2 is last cell on row
cmp_ret = -1;
} else {
// compare qualifiers
ObString qualifier1 = cell1.get_qualifier();
ObString qualifier2 = cell2.get_qualifier();
if(common::ObQueryFlag::Reverse == scan_order){
cmp_ret = qualifier2.compare(qualifier1);
} else {
cmp_ret = qualifier1.compare(qualifier2);
}
if (0 == cmp_ret) {
// compare timestamps in ascending order (the value of timestamp is negative)
int64_t ts1 = cell1.get_timestamp();
int64_t ts2 = cell2.get_timestamp();
if (ts1 == ts2) {
// one of the cells could be ObHTableFirstOnRowCell or ObHTableFirstOnRowColCell
if (common::ObQueryFlag::Reverse == scan_order) {
cmp_ret = static_cast<int>(cell2.get_type()) - static_cast<int>(cell1.get_type());
} else {
cmp_ret = static_cast<int>(cell1.get_type()) - static_cast<int>(cell2.get_type());
}
} else if (ts1 < ts2) {
cmp_ret = -1;
} else {
cmp_ret = 1;
}
}
}
}
return cmp_ret;
}
int ObHTableUtils::compare_qualifier(const common::ObString &cq1, const common::ObString &cq2)
{
return cq1.compare(cq2);
}
int ObHTableUtils::compare_rowkey(const common::ObString &rk1, const common::ObString &rk2)
{
return rk1.compare(rk2);
}
int ObHTableUtils::compare_rowkey(const ObHTableCell &cell1, const ObHTableCell &cell2)
{
return compare_rowkey(cell1.get_rowkey(), cell2.get_rowkey());
}
int ObHTableUtils::java_bytes_to_int64(const ObString &bytes, int64_t &val)
{
int ret = OB_SUCCESS;
if (bytes.length() != sizeof(int64_t)) {
ret = OB_INVALID_DATA;
LOG_WARN("length should be 8 bytes", K(ret), "len", bytes.length());
} else {
// In Java, data is stored in big-endian format (also called network order).
const uint64_t *big_endian_64bits = reinterpret_cast<const uint64_t*>(bytes.ptr());
val = be64toh(*big_endian_64bits);
}
return ret;
}
int ObHTableUtils::int64_to_java_bytes(int64_t val, char bytes[8])
{
uint64_t big_endian_64bits = htobe64(val);
memcpy(bytes, &big_endian_64bits, sizeof(int64_t));
return OB_SUCCESS;
}

View File

@ -0,0 +1,313 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef _OB_HTABLE_UTILS_H
#define _OB_HTABLE_UTILS_H 1
#include "common/row/ob_row.h"
#include "lib/string/ob_string.h"
#include "share/table/ob_table.h"
#include <stdint.h>
namespace oceanbase
{
namespace table
{
// Interface ObHTableCell
class ObHTableCell
{
public:
ObHTableCell() {}
virtual ~ObHTableCell() {}
virtual common::ObString get_rowkey() const = 0;
virtual common::ObString get_qualifier() const = 0;
virtual int64_t get_timestamp() const = 0;
virtual common::ObString get_value() const = 0;
enum class Type
{
FIRST_ON_ROW = 0 /*virtual cell which present the first cell on row*/,
FIRST_ON_COL = 1 /*virtual cell which present the first cell on column*/,
NORMAL = 2,
LAST_ON_COL = 3 /*virtual cell which present the last cell on column, "bigger" than other cells*/,
LAST_ON_ROW = 4 /*virtual cell which present the last cell on row, "bigger" than other cells*/
};
// true for
virtual Type get_type() const = 0;
TO_STRING_KV(ObHTableConstants::ROWKEY_CNAME, get_rowkey(),
ObHTableConstants::CQ_CNAME, get_qualifier(),
ObHTableConstants::VERSION_CNAME, get_timestamp(),
ObHTableConstants::VALUE_CNAME, get_value());
private:
DISALLOW_COPY_AND_ASSIGN(ObHTableCell);
};
class ObHTableCellEntity: public ObHTableCell
{
public:
explicit ObHTableCellEntity(common::ObNewRow *ob_row);
ObHTableCellEntity();
virtual ~ObHTableCellEntity();
void set_ob_row(common::ObNewRow *ob_row) { ob_row_ = ob_row; }
const common::ObNewRow* get_ob_row() const { return ob_row_; }
virtual common::ObString get_rowkey() const override;
virtual common::ObString get_qualifier() const override;
virtual int64_t get_timestamp() const override;
virtual common::ObString get_value() const override;
virtual Type get_type() const { return Type::NORMAL; }
private:
common::ObNewRow *ob_row_;
DISALLOW_COPY_AND_ASSIGN(ObHTableCellEntity);
};
class ObHTableEmptyCell: public ObHTableCell
{
public:
ObHTableEmptyCell() {}
virtual ~ObHTableEmptyCell() {}
virtual common::ObString get_rowkey() const override { return common::ObString(); }
virtual common::ObString get_qualifier() const override { return common::ObString(); }
virtual common::ObString get_value() const override { return common::ObString(); }
private:
DISALLOW_COPY_AND_ASSIGN(ObHTableEmptyCell);
};
class ObHTableFirstOnRowCell: public ObHTableEmptyCell
{
public:
ObHTableFirstOnRowCell(const common::ObString &rowkey)
:rowkey_(rowkey)
{}
virtual ~ObHTableFirstOnRowCell() {}
virtual common::ObString get_rowkey() const override { return rowkey_; }
virtual int64_t get_timestamp() const override { return ObHTableConstants::LATEST_TIMESTAMP; }
virtual Type get_type() const { return Type::FIRST_ON_ROW; }
private:
common::ObString rowkey_;
DISALLOW_COPY_AND_ASSIGN(ObHTableFirstOnRowCell);
};
class ObHTableFirstOnRowColCell: public ObHTableFirstOnRowCell
{
public:
ObHTableFirstOnRowColCell(const common::ObString &rowkey, const common::ObString &qualifier)
:ObHTableFirstOnRowCell(rowkey),
qualifier_(qualifier)
{}
virtual ~ObHTableFirstOnRowColCell() {}
virtual common::ObString get_qualifier() const override { return qualifier_; }
virtual Type get_type() const { return Type::FIRST_ON_COL; }
private:
common::ObString qualifier_;
DISALLOW_COPY_AND_ASSIGN(ObHTableFirstOnRowColCell);
};
class ObHTableLastOnRowCell: public ObHTableEmptyCell
{
public:
ObHTableLastOnRowCell(const common::ObString &rowkey)
:rowkey_(rowkey)
{}
virtual ~ObHTableLastOnRowCell() {}
virtual common::ObString get_rowkey() const override { return rowkey_; }
virtual int64_t get_timestamp() const override { return ObHTableConstants::OLDEST_TIMESTAMP; }
virtual Type get_type() const { return Type::LAST_ON_ROW; }
private:
common::ObString rowkey_;
DISALLOW_COPY_AND_ASSIGN(ObHTableLastOnRowCell);
};
class ObHTableLastOnRowColCell: public ObHTableLastOnRowCell
{
public:
ObHTableLastOnRowColCell(const common::ObString &rowkey, const common::ObString &qualifier)
:ObHTableLastOnRowCell(rowkey),
qualifier_(qualifier)
{}
virtual ~ObHTableLastOnRowColCell() {}
virtual common::ObString get_qualifier() const override { return qualifier_; }
virtual Type get_type() const { return Type::LAST_ON_COL; }
private:
common::ObString qualifier_;
DISALLOW_COPY_AND_ASSIGN(ObHTableLastOnRowColCell);
};
class ObHTableCellEntity2: public ObHTableCell
{
public:
explicit ObHTableCellEntity2(const ObITableEntity *entity)
:entity_(entity)
{}
virtual ~ObHTableCellEntity2() {}
virtual common::ObString get_rowkey() const override;
virtual common::ObString get_qualifier() const override;
virtual int64_t get_timestamp() const override;
virtual common::ObString get_value() const override;
virtual Type get_type() const { return Type::NORMAL; }
private:
const ObITableEntity *entity_;
DISALLOW_COPY_AND_ASSIGN(ObHTableCellEntity2);
};
class ObHTableCellEntity3: public ObHTableCell
{
public:
explicit ObHTableCellEntity3(const ObITableEntity *entity)
:entity_(entity),
last_get_is_null_(false)
{}
virtual ~ObHTableCellEntity3() {}
virtual common::ObString get_rowkey() const override;
virtual common::ObString get_qualifier() const override;
virtual int64_t get_timestamp() const override;
virtual common::ObString get_value() const override;
bool last_get_is_null() const { return last_get_is_null_; }
virtual Type get_type() const { return Type::NORMAL; }
private:
const ObITableEntity *entity_;
mutable bool last_get_is_null_;
DISALLOW_COPY_AND_ASSIGN(ObHTableCellEntity3);
};
/// Represents an interval of version timestamps.
/// [min_stamp, max_stamp), e.g. [3, 5)
class ObTimeRange final
{
public:
ObTimeRange()
:min_stamp_(ObHTableConstants::INITIAL_MIN_STAMP),
max_stamp_(ObHTableConstants::INITIAL_MAX_STAMP),
is_all_time_(true)
{}
ObTimeRange(int64_t min, int64_t max)
:min_stamp_(min),
max_stamp_(max)
{
is_all_time_ = is_all_time();
}
/**
* Compare the timestamp to timerange.
* @return -1 if timestamp is less than timerange,
* 0 if timestamp is within timerange,
* 1 if timestamp is greater than timerange
*/
inline int compare(int64_t timestamp) const
{
int cmp_ret = 0;
if (is_all_time()) {
cmp_ret = 0;
} else if (timestamp < min_stamp_) {
cmp_ret = -1;
} else if (timestamp >= max_stamp_) {
cmp_ret = 1;
}
return cmp_ret;
}
private:
bool is_all_time() const
{
return ObHTableConstants::INITIAL_MIN_STAMP == min_stamp_
&& ObHTableConstants::INITIAL_MAX_STAMP == max_stamp_;
}
private:
int64_t min_stamp_;
int64_t max_stamp_;
bool is_all_time_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObTimeRange);
};
/// (min_stamp, max_stamp], e.g. (-5, -3]
class ObNegativeTimeRange final
{
static constexpr int64_t INITIAL_NEG_MIN_STAMP = -INT64_MAX;
static constexpr int64_t INITIAL_NEG_MAX_STAMP = 0;
public:
ObNegativeTimeRange()
:min_stamp_(INITIAL_NEG_MIN_STAMP),
max_stamp_(INITIAL_NEG_MAX_STAMP)
{
is_all_time_ = is_all_time();
}
ObNegativeTimeRange(int64_t min, int64_t max)
:min_stamp_(min),
max_stamp_(max)
{
is_all_time_ = is_all_time();
} /**
* Compare the timestamp to timerange.
* @return -1 if timestamp is less than timerange,
* 0 if timestamp is within timerange,
* 1 if timestamp is greater than timerange
*/
inline int compare(int64_t timestamp) const
{
int cmp_ret = 0;
if (is_all_time()) {
cmp_ret = 0;
} else if (timestamp <= min_stamp_) {
cmp_ret = 1;
} else if (timestamp > max_stamp_) {
cmp_ret = -1;
}
return cmp_ret;
}
TO_STRING_KV(K_(min_stamp), K_(max_stamp), K_(is_all_time));
private:
bool is_all_time() const
{
return INITIAL_NEG_MIN_STAMP == min_stamp_
&& INITIAL_NEG_MAX_STAMP == max_stamp_;
}
private:
int64_t min_stamp_;
int64_t max_stamp_;
bool is_all_time_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObNegativeTimeRange);
};
class ObHTableUtils
{
public:
/// Create a Cell that is larger than all other possible Cells for the given Cell's rk:cf:q
static int create_last_cell_on_row_col(common::ObArenaAllocator &allocator, const ObHTableCell &cell, ObHTableCell *&new_cell);
/// Create a Cell that is smaller than all other possible Cells for the given Cell's rk:cf and passed qualifier.
static int create_first_cell_on_row_col(common::ObArenaAllocator &allocator, const ObHTableCell &cell, const common::ObString &qualifier, ObHTableCell *&new_cell);
/// Create a Cell that is larger than all other possible Cells for the given Cell's row.
static int create_last_cell_on_row(common::ObArenaAllocator &allocator, const ObHTableCell &cell, ObHTableCell *&new_cell);
static int compare_qualifier(const common::ObString &cq1, const common::ObString &cq2);
static int compare_rowkey(const common::ObString &rk1, const common::ObString &rk2);
static int compare_rowkey(const ObHTableCell &cell1, const ObHTableCell &cell2);
static int compare_cell(const ObHTableCell &cell1, const ObHTableCell &cell2, common::ObQueryFlag::ScanOrder &scan_order);
static int64_t current_time_millis() { return common::ObTimeUtility::current_time() / 1000; }
static int java_bytes_to_int64(const ObString &bytes, int64_t &val);
static int int64_to_java_bytes(int64_t val, char bytes[8]);
private:
ObHTableUtils() = delete;
~ObHTableUtils() = delete;
};
} // end namespace table
} // end namespace oceanbase
#endif /* _OB_HTABLE_UTILS_H */

View File

@ -19,7 +19,7 @@
#include "sql/optimizer/ob_table_location.h" // ObTableLocation
#include "lib/stat/ob_diagnose_info.h"
#include "lib/stat/ob_session_stat.h"
#include "ob_htable_utils.h"
using namespace oceanbase::observer;
using namespace oceanbase::common;
using namespace oceanbase::table;
@ -40,13 +40,27 @@ int ObTableBatchExecuteP::deserialize()
arg_.batch_operation_.set_entity_factory(&default_entity_factory_);
result_.set_entity_factory(&default_entity_factory_);
int ret = ParentType::deserialize();
if (OB_SUCC(ret) && ObTableEntityType::ET_HKV == arg_.entity_type_) {
// for HKV, modify the value of timestamp to be negative
const int64_t N = arg_.batch_operation_.count();
for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i)
{
ObITableEntity *entity = nullptr;
if (OB_FAIL(const_cast<ObTableOperation&>(arg_.batch_operation_.at(i)).get_entity(entity))) {
LOG_WARN("failed to get entity", K(ret), K(i));
} else if (OB_FAIL(ObTableRpcProcessorUtil::negate_htable_timestamp(*entity))) {
LOG_WARN("failed to negate timestamp value", K(ret));
}
} // end for
}
return ret;
}
int ObTableBatchExecuteP::check_arg()
{
int ret = OB_SUCCESS;
if (arg_.consistency_level_ != ObTableConsistencyLevel::STRONG) {
if (!(arg_.consistency_level_ == ObTableConsistencyLevel::STRONG ||
arg_.consistency_level_ == ObTableConsistencyLevel::EVENTUAL)) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("some options not supported yet", K(ret),
"consistency_level", arg_.consistency_level_);
@ -102,7 +116,22 @@ int ObTableBatchExecuteP::response(const int retcode)
{
int ret = OB_SUCCESS;
if (!need_retry_in_queue_ && !did_async_end_trans()) {
ret = ObRpcProcessor::response(retcode);
// For HKV table, modify the value of timetamp to be positive
if (OB_SUCC(ret) && ObTableEntityType::ET_HKV == arg_.entity_type_) {
const int64_t N = result_.count();
for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i)
{
ObITableEntity *entity = nullptr;
if (OB_FAIL(result_.at(i).get_entity(entity))) {
LOG_WARN("failed to get entity", K(ret), K(i));
} else if (OB_FAIL(ObTableRpcProcessorUtil::negate_htable_timestamp(*entity))) {
LOG_WARN("failed to negate timestamp value", K(ret));
}
} // end for
}
if (OB_SUCC(ret)) {
ret = ObRpcProcessor::response(retcode);
}
}
return ret;
}
@ -140,16 +169,26 @@ int ObTableBatchExecuteP::try_process()
ret = multi_insert();
break;
case ObTableOperationType::DEL:
stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_DELETE;
ret = multi_delete();
if (ObTableEntityType::ET_HKV == arg_.entity_type_) {
stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_DELETE;
ret = htable_delete();
} else {
stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_DELETE;
ret = multi_delete();
}
break;
case ObTableOperationType::UPDATE:
stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_UPDATE;
ret = multi_update();
break;
case ObTableOperationType::INSERT_OR_UPDATE:
stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_INSERT_OR_UPDATE;
ret = multi_insert_or_update();
if (ObTableEntityType::ET_HKV == arg_.entity_type_) {
stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_PUT;
ret = htable_put();
} else {
stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_INSERT_OR_UPDATE;
ret = multi_insert_or_update();
}
break;
case ObTableOperationType::REPLACE:
stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_REPLACE;
@ -169,9 +208,15 @@ int ObTableBatchExecuteP::try_process()
break;
}
} else {
// complex batch hybrid operation
stat_event_type_ = ObTableProccessType::TABLE_API_BATCH_HYBRID;
ret = batch_execute(false);
if (ObTableEntityType::ET_HKV == arg_.entity_type_) {
// HTable mutate_row(RowMutations)
stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_HYBRID;
ret = htable_mutate_row();
} else {
// complex batch hybrid operation
stat_event_type_ = ObTableProccessType::TABLE_API_BATCH_HYBRID;
ret = batch_execute(false);
}
}
}
@ -277,6 +322,54 @@ int ObTableBatchExecuteP::multi_insert_or_update()
return ret;
}
int ObTableBatchExecuteP::htable_put()
{
int ret = OB_SUCCESS;
const ObTableBatchOperation &batch_operation = arg_.batch_operation_;
const bool is_readonly = false;
uint64_t table_id = OB_INVALID_ID;
ObSEArray<int64_t, 1> part_ids;
if (OB_FAIL(check_arg2())) {
} else if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) {
LOG_WARN("failed to get table id", K(ret));
} else if (OB_FAIL(get_partition_ids(table_id, part_ids))) {
LOG_WARN("failed to get part id", K(ret));
} else if (1 != part_ids.count()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("should have one partition", K(ret), K(part_ids));
} else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_INSERT, table_id, part_ids, get_timeout_ts()))) {
LOG_WARN("failed to start transaction", K(ret));
} else {
int64_t affected_rows = 0;
ObHTablePutExecutor put_executor(allocator_,
table_id,
part_ids.at(0),
get_timeout_ts(),
this,
table_service_,
part_service_);
ret = put_executor.htable_put(batch_operation, affected_rows);
if (OB_SUCC(ret)) {
ObTableOperationResult single_op_result;
single_op_result.set_entity(result_entity_);
single_op_result.set_type(ObTableOperationType::INSERT_OR_UPDATE);
single_op_result.set_errno(ret);
single_op_result.set_affected_rows(affected_rows);
result_.reset();
if (OB_FAIL(result_.push_back(single_op_result))) {
LOG_WARN("failed to add result", K(ret));
}
}
}
int tmp_ret = ret;
if (OB_FAIL(end_trans(OB_SUCCESS != ret, req_, get_timeout_ts()))) {
LOG_WARN("failed to end trans");
}
ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret;
return ret;
}
int ObTableBatchExecuteP::multi_get()
{
int ret = OB_SUCCESS;
@ -288,6 +381,7 @@ int ObTableBatchExecuteP::multi_get()
arg_.binlog_row_image_type_);
ObSEArray<int64_t, 1> part_ids;
const bool is_readonly = true;
const ObTableConsistencyLevel consistency_level = arg_.consistency_level_;
if (OB_FAIL(check_arg2())) {
} else if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) {
LOG_WARN("failed to get table id", K(ret));
@ -297,7 +391,7 @@ int ObTableBatchExecuteP::multi_get()
ret = OB_NOT_SUPPORTED;
LOG_WARN("should have one partition", K(ret), K(part_ids));
} else if (FALSE_IT(table_service_ctx_.param_partition_id() = part_ids.at(0))) {
} else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, table_id, part_ids, get_timeout_ts()))) {
} else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, consistency_level, table_id, part_ids, get_timeout_ts()))) {
LOG_WARN("failed to start readonly transaction", K(ret));
} else if (OB_FAIL(table_service_->multi_get(table_service_ctx_, arg_.batch_operation_, result_))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
@ -348,6 +442,54 @@ int ObTableBatchExecuteP::multi_delete()
return ret;
}
int ObTableBatchExecuteP::htable_delete()
{
int ret = OB_SUCCESS;
const ObTableBatchOperation &batch_operation = arg_.batch_operation_;
const bool is_readonly = false;
uint64_t table_id = OB_INVALID_ID;
ObSEArray<int64_t, 1> part_ids;
if (OB_FAIL(check_arg2())) {
} else if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) {
LOG_WARN("failed to get table id", K(ret));
} else if (OB_FAIL(get_partition_ids(table_id, part_ids))) {
LOG_WARN("failed to get part id", K(ret));
} else if (1 != part_ids.count()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("should have one partition", K(ret), K(part_ids));
} else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_DELETE, table_id, part_ids, get_timeout_ts()))) {
LOG_WARN("failed to start transaction", K(ret));
} else {
int64_t affected_rows = 0;
ObHTableDeleteExecutor delete_executor(allocator_,
table_id,
part_ids.at(0),
get_timeout_ts(),
this,
table_service_,
part_service_);
ret = delete_executor.htable_delete(batch_operation, affected_rows);
if (OB_SUCC(ret)) {
ObTableOperationResult single_op_result;
single_op_result.set_entity(result_entity_);
single_op_result.set_type(ObTableOperationType::DEL);
single_op_result.set_errno(ret);
single_op_result.set_affected_rows(affected_rows);
result_.reset();
if (OB_FAIL(result_.push_back(single_op_result))) {
LOG_WARN("failed to add result", K(ret));
}
}
}
int tmp_ret = ret;
if (OB_FAIL(end_trans(OB_SUCCESS != ret, req_, get_timeout_ts()))) {
LOG_WARN("failed to end trans");
}
ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret;
return ret;
}
int ObTableBatchExecuteP::multi_insert()
{
int ret = OB_SUCCESS;
@ -465,6 +607,7 @@ int ObTableBatchExecuteP::batch_execute(bool is_readonly)
arg_.returning_affected_entity_,
arg_.returning_rowkey_);
ObSEArray<int64_t, 1> part_ids;
const ObTableConsistencyLevel consistency_level = arg_.consistency_level_;
if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) {
LOG_WARN("failed to get table id", K(ret));
} else if (OB_FAIL(get_partition_ids(table_id, part_ids))) {
@ -474,7 +617,7 @@ int ObTableBatchExecuteP::batch_execute(bool is_readonly)
LOG_WARN("should have one partition", K(ret), K(part_ids));
} else if (FALSE_IT(table_service_ctx_.param_partition_id() = part_ids.at(0))) {
} else if (OB_FAIL(start_trans(is_readonly, (is_readonly ? sql::stmt::T_SELECT : sql::stmt::T_UPDATE),
table_id, part_ids, get_timeout_ts()))) {
consistency_level, table_id, part_ids, get_timeout_ts()))) {
LOG_WARN("failed to start transaction", K(ret));
} else if (OB_FAIL(table_service_->batch_execute(table_service_ctx_, batch_operation, result_))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
@ -488,3 +631,74 @@ int ObTableBatchExecuteP::batch_execute(bool is_readonly)
ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret;
return ret;
}
int ObTableBatchExecuteP::htable_mutate_row()
{
int ret = OB_SUCCESS;
const ObTableBatchOperation &batch_operation = arg_.batch_operation_;
const bool is_readonly = false;
uint64_t table_id = OB_INVALID_ID;
ObSEArray<int64_t, 1> part_ids;
int64_t now_ms = -ObHTableUtils::current_time_millis();
if (OB_FAIL(check_arg2())) {
} else if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) {
LOG_WARN("failed to get table id", K(ret));
} else if (OB_FAIL(get_partition_ids(table_id, part_ids))) {
LOG_WARN("failed to get part id", K(ret));
} else if (1 != part_ids.count()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("should have one partition", K(ret), K(part_ids));
} else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_DELETE, table_id, part_ids, get_timeout_ts()))) {
LOG_WARN("failed to start transaction", K(ret));
} else {
int64_t N = batch_operation.count();
for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i)
{
// execute each mutation one by one
const ObTableOperation &table_operation = batch_operation.at(i);
ObTableBatchOperation batch_ops;
if (OB_FAIL(batch_ops.add(table_operation))) {
LOG_WARN("failed to add", K(ret));
break;
}
switch(table_operation.type()) {
case ObTableOperationType::INSERT_OR_UPDATE:
{
int64_t affected_rows = 0;
ObHTablePutExecutor put_executor(allocator_,
table_id,
part_ids.at(0),
get_timeout_ts(),
this,
table_service_,
part_service_);
ret = put_executor.htable_put(batch_ops, affected_rows, now_ms);
}
break;
case ObTableOperationType::DEL:
{
int64_t affected_rows = 0;
ObHTableDeleteExecutor delete_executor(allocator_,
table_id,
part_ids.at(0),
get_timeout_ts(),
this,
table_service_,
part_service_);
ret = delete_executor.htable_delete(batch_ops, affected_rows);
}
break;
default:
ret = OB_NOT_SUPPORTED;
LOG_WARN("not supported mutation type", K(ret), K(table_operation));
break;
} // end switch
} // end for
}
int tmp_ret = ret;
if (OB_FAIL(end_trans(OB_SUCCESS != ret, req_, get_timeout_ts()))) {
LOG_WARN("failed to end trans");
}
ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret;
return ret;
}

View File

@ -50,6 +50,9 @@ private:
int multi_replace();
int multi_update();
int batch_execute(bool is_readonly);
int htable_delete();
int htable_put();
int htable_mutate_row();
private:
static const int64_t COMMON_COLUMN_NUM = 16;
table::ObTableEntityFactory<table::ObTableEntity> default_entity_factory_;

View File

@ -64,13 +64,18 @@ int ObTableApiExecuteP::deserialize()
arg_.table_operation_.set_entity(request_entity_);
result_.set_entity(result_entity_);
int ret = ParentType::deserialize();
if (OB_SUCC(ret) && ObTableEntityType::ET_HKV == arg_.entity_type_) {
// @note modify the timestamp to be negative
ret = ObTableRpcProcessorUtil::negate_htable_timestamp(request_entity_);
}
return ret;
}
int ObTableApiExecuteP::check_arg()
{
int ret = OB_SUCCESS;
if (arg_.consistency_level_ != ObTableConsistencyLevel::STRONG) {
if (!(arg_.consistency_level_ == ObTableConsistencyLevel::STRONG ||
arg_.consistency_level_ == ObTableConsistencyLevel::EVENTUAL)) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("some options not supported yet", K(ret),
"consistency_level", arg_.consistency_level_,
@ -207,7 +212,13 @@ int ObTableApiExecuteP::response(const int retcode)
{
int ret = OB_SUCCESS;
if (!need_retry_in_queue_ && !did_async_end_trans()) {
ret = ObRpcProcessor::response(retcode);
if (OB_SUCC(ret) && ObTableEntityType::ET_HKV == arg_.entity_type_) {
// @note modify the value of timestamp to be positive
ret = ObTableRpcProcessorUtil::negate_htable_timestamp(result_entity_);
}
if (OB_SUCC(ret)) {
ret = ObRpcProcessor::response(retcode);
}
}
return ret;
}
@ -255,6 +266,7 @@ int ObTableApiExecuteP::process_get()
arg_.entity_type_,
arg_.binlog_row_image_type_);
const bool is_readonly = true;
const ObTableConsistencyLevel consistency_level = arg_.consistency_level_;
ObRowkey rowkey = const_cast<ObITableEntity&>(arg_.table_operation_.entity()).get_rowkey();
ObSEArray<int64_t, 1> part_ids;
if (OB_FAIL(check_arg2())) {
@ -264,7 +276,7 @@ int ObTableApiExecuteP::process_get()
LOG_WARN("failed to get partition id", K(ret));
} else if (OB_FAIL(part_ids.push_back(get_ctx_.param_partition_id()))) {
LOG_WARN("failed to push back", K(ret));
} else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, table_id, part_ids, get_timeout_ts()))) {
} else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, consistency_level, table_id, part_ids, get_timeout_ts()))) {
LOG_WARN("failed to start readonly transaction", K(ret));
} else if (OB_FAIL(table_service_->execute_get(get_ctx_, arg_.table_operation_, result_))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret) {

View File

@ -0,0 +1,292 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX SERVER
#include "ob_table_query_and_mutate_processor.h"
#include "ob_table_rpc_processor_util.h"
#include "observer/ob_service.h"
#include "storage/ob_partition_service.h"
#include "ob_table_end_trans_cb.h"
#include "sql/optimizer/ob_table_location.h" // ObTableLocation
#include "lib/stat/ob_diagnose_info.h"
#include "lib/stat/ob_session_stat.h"
#include "ob_htable_utils.h"
using namespace oceanbase::observer;
using namespace oceanbase::common;
using namespace oceanbase::table;
using namespace oceanbase::share;
using namespace oceanbase::sql;
ObTableQueryAndMutateP::ObTableQueryAndMutateP(const ObGlobalContext &gctx)
:ObTableRpcProcessor(gctx),
allocator_(ObModIds::TABLE_PROC),
query_ctx_(allocator_)
{
}
int ObTableQueryAndMutateP::deserialize()
{
arg_.query_and_mutate_.set_deserialize_allocator(&allocator_);
arg_.query_and_mutate_.set_entity_factory(&default_entity_factory_);
int ret = ParentType::deserialize();
if (OB_SUCC(ret) && ObTableEntityType::ET_HKV == arg_.entity_type_) {
// For HKV table, modify the timestamp value to be negative
ObTableBatchOperation &mutations = arg_.query_and_mutate_.get_mutations();
const int64_t N = mutations.count();
for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i)
{
ObITableEntity *entity = nullptr;
ObTableOperation &mutation = const_cast<ObTableOperation&>(mutations.at(i));
if (OB_FAIL(mutation.get_entity(entity))) {
LOG_WARN("failed to get entity", K(ret), K(i));
} else if (OB_FAIL(ObTableRpcProcessorUtil::negate_htable_timestamp(*entity))) {
LOG_WARN("failed to negate timestamp value", K(ret));
}
} // end for
}
return ret;
}
int ObTableQueryAndMutateP::check_arg()
{
int ret = OB_SUCCESS;
ObTableQuery &query = arg_.query_and_mutate_.get_query();
ObHTableFilter &hfilter = query.htable_filter();
ObTableBatchOperation &mutations = arg_.query_and_mutate_.get_mutations();
if (!query.is_valid()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid table query request", K(ret), K(query));
} else if (!hfilter.is_valid()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("QueryAndMutate only supports hbase model table for now", K(ret));
} else if (mutations.count() <= 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("should have at least one mutation operation", K(ret), K(mutations));
} else {
// these options are meaningless for QueryAndMutate users but we should control them internally
query.set_batch(1); // mutate for each row
query.set_max_result_size(-1);
hfilter.set_max_versions(1);
hfilter.set_row_offset_per_column_family(0);
hfilter.set_max_results_per_column_family(-1);
}
return ret;
}
void ObTableQueryAndMutateP::audit_on_finish()
{
audit_record_.consistency_level_ = ObConsistencyLevel::STRONG; // todo: exact consistency
audit_record_.return_rows_ = arg_.query_and_mutate_.return_affected_entity() ? result_.affected_entity_.get_row_count() : 0;
audit_record_.table_scan_ = true; // todo: exact judgement
audit_record_.affected_rows_ = result_.affected_rows_;
audit_record_.try_cnt_ = retry_count_ + 1;
}
uint64_t ObTableQueryAndMutateP::get_request_checksum()
{
uint64_t checksum = 0;
checksum = ob_crc64(checksum, arg_.table_name_.ptr(), arg_.table_name_.length());
const uint64_t op_checksum = arg_.query_and_mutate_.get_checksum();
checksum = ob_crc64(checksum, &op_checksum, sizeof(op_checksum));
checksum = ob_crc64(checksum, &arg_.binlog_row_image_type_, sizeof(arg_.binlog_row_image_type_));
return checksum;
}
void ObTableQueryAndMutateP::reset_ctx()
{
query_ctx_.reset_query_ctx(part_service_);
need_retry_in_queue_ = false;
one_result_.reset();
ObTableApiProcessorBase::reset_ctx();
}
ObTableAPITransCb *ObTableQueryAndMutateP::new_callback(rpc::ObRequest *req)
{
UNUSED(req);
return nullptr;
}
int ObTableQueryAndMutateP::get_partition_ids(uint64_t table_id, ObIArray<int64_t> &part_ids)
{
int ret = OB_SUCCESS;
uint64_t partition_id = arg_.partition_id_;
if (OB_INVALID_ID == partition_id) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("partitioned table not supported", K(ret), K(table_id));
} else {
if (OB_FAIL(part_ids.push_back(partition_id))) {
LOG_WARN("failed to push back", K(ret));
}
}
return ret;
}
int ObTableQueryAndMutateP::try_process()
{
int ret = OB_SUCCESS;
const ObTableQuery &query = arg_.query_and_mutate_.get_query();
ObTableBatchOperation &mutations = arg_.query_and_mutate_.get_mutations();
int64_t rpc_timeout = 0;
if (NULL != rpc_pkt_) {
rpc_timeout = rpc_pkt_->get_timeout();
}
uint64_t &table_id = query_ctx_.param_table_id();
query_ctx_.init_param(get_timeout_ts(), this, &allocator_,
false/*ignored*/,
arg_.entity_type_,
table::ObBinlogRowImageType::MINIMAL/*ignored*/);
ObSEArray<int64_t, 1> part_ids;
const bool is_readonly = false;
ObTableQueryResultIterator *result_iterator = nullptr;
int32_t result_count = 0;
int64_t affected_rows = 0;
if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) {
LOG_WARN("failed to get table id", K(ret));
} else if (OB_FAIL(get_partition_ids(table_id, part_ids))) {
LOG_WARN("failed to get part id", K(ret));
} else if (1 != part_ids.count()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("should have one partition", K(ret), K(part_ids));
} else if (FALSE_IT(query_ctx_.param_partition_id() = part_ids.at(0))) {
} else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_UPDATE, table_id, part_ids,
get_timeout_ts()))) {
LOG_WARN("failed to start readonly transaction", K(ret));
} else if (OB_FAIL(table_service_->execute_query(query_ctx_, query,
one_result_, result_iterator))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
LOG_WARN("failed to execute query", K(ret), K(table_id));
}
} else {
// one_result references to result_
ObTableQueryResult *one_result = nullptr;
// htable queryAndXXX only check one row
ret = result_iterator->get_next_result(one_result);
if (OB_ITER_END == ret || OB_SUCC(ret)) {
ret = OB_SUCCESS;
one_result = &one_result_; // empty result is OK for APPEND and INCREMENT
const ObTableOperation &mutation = mutations.at(0);
switch(mutation.type()) {
case ObTableOperationType::DEL: // checkAndDelete
stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_CHECK_AND_DELETE;
if (one_result->get_row_count() > 0) { // not empty result means check passed
affected_rows = 1;
int64_t deleted_cells = 0;
ObHTableDeleteExecutor delete_executor(allocator_,
table_id,
part_ids.at(0),
get_timeout_ts(),
this,
table_service_,
part_service_);
ret = delete_executor.htable_delete(mutations, deleted_cells);
}
break;
case ObTableOperationType::INSERT_OR_UPDATE: // checkAndPut
stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_CHECK_AND_PUT;
if (one_result->get_row_count() > 0) { // not empty result means check passed
affected_rows = 1;
int64_t put_rows = 0;
ObHTablePutExecutor put_executor(allocator_,
table_id,
part_ids.at(0),
get_timeout_ts(),
this,
table_service_,
part_service_);
ret = put_executor.htable_put(mutations, put_rows);
}
break;
case ObTableOperationType::INCREMENT: // Increment
stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_INCREMENT;
{ // one_result->get_row_count() >= 0
affected_rows = 1;
ObHTableIncrementExecutor inc_executor(ObTableOperationType::INCREMENT,
allocator_,
table_id,
part_ids.at(0),
get_timeout_ts(),
this,
table_service_,
part_service_);
int64_t put_cells = 0;
table::ObTableQueryResult *results = NULL;
if (arg_.query_and_mutate_.return_affected_entity()) {
results = &result_.affected_entity_;
}
ret = inc_executor.htable_increment(*one_result, mutations,
put_cells, results);
}
break;
case ObTableOperationType::APPEND: // Append
stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_APPEND;
{ // one_result->get_row_count() >= 0
affected_rows = 1;
ObHTableIncrementExecutor apd_executor(ObTableOperationType::APPEND,
allocator_,
table_id,
part_ids.at(0),
get_timeout_ts(),
this,
table_service_,
part_service_);
int64_t put_cells = 0;
table::ObTableQueryResult *results = NULL;
if (arg_.query_and_mutate_.return_affected_entity()) {
results = &result_.affected_entity_;
}
ret = apd_executor.htable_increment(*one_result, mutations,
put_cells, results);
}
break;
default:
ret = OB_NOT_SUPPORTED;
LOG_WARN("not supported mutation type", K(ret), "type", mutation.type());
break;
}
} else {
LOG_WARN("failed to get one row", K(ret));
}
NG_TRACE_EXT(tag1, OB_ID(found_rows), result_count,
OB_ID(affected_rows), affected_rows);
}
query_ctx_.destroy_result_iterator(part_service_);
bool need_rollback_trans = (OB_SUCCESS != ret);
int tmp_ret = ret;
const bool use_sync = true;
if (OB_FAIL(end_trans(need_rollback_trans, req_, get_timeout_ts(), use_sync))) {
LOG_WARN("failed to end trans", K(ret), "rollback", need_rollback_trans);
}
ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret;
if (OB_SUCC(ret)) {
result_.affected_rows_ = affected_rows;
} else {
result_.affected_rows_ = 0;
}
// record events
audit_row_count_ = 1;
#ifndef NDEBUG
// debug mode
LOG_INFO("[TABLE] execute query_and_mutate", K(ret), K_(arg), K(rpc_timeout),
K_(retry_count), K(result_count));
#else
// release mode
LOG_TRACE("[TABLE] execute query_and_mutate", K(ret), K_(arg),
K(rpc_timeout), K_(retry_count),
"receive_ts", get_receive_timestamp(), K(result_count));
#endif
return ret;
}

View File

@ -0,0 +1,56 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef _OB_TABLE_QUERY_AND_MUTATE_PROCESSOR_H
#define _OB_TABLE_QUERY_AND_MUTATE_PROCESSOR_H 1
#include "rpc/obrpc/ob_rpc_proxy.h"
#include "rpc/obrpc/ob_rpc_processor.h"
#include "share/table/ob_table_rpc_proxy.h"
#include "ob_table_rpc_processor.h"
#include "ob_table_service.h"
namespace oceanbase
{
namespace observer
{
class ObTableQueryAndMutateP: public ObTableRpcProcessor<obrpc::ObTableRpcProxy::ObRpc<obrpc::OB_TABLE_API_QUERY_AND_MUTATE> >
{
typedef ObTableRpcProcessor<obrpc::ObTableRpcProxy::ObRpc<obrpc::OB_TABLE_API_QUERY_AND_MUTATE> > ParentType;
public:
explicit ObTableQueryAndMutateP(const ObGlobalContext &gctx);
virtual ~ObTableQueryAndMutateP() {}
virtual int deserialize() override;
protected:
virtual int check_arg() override;
virtual int try_process() override;
virtual void reset_ctx() override;
virtual table::ObTableAPITransCb *new_callback(rpc::ObRequest *req) override;
virtual void audit_on_finish() override;
virtual uint64_t get_request_checksum() override;
private:
int get_partition_ids(uint64_t table_id, common::ObIArray<int64_t> &part_ids);
int check_rowkey_and_generate_mutations(
ObTableQueryResult &one_row,
ObTableBatchOperation *&mutations);
DISALLOW_COPY_AND_ASSIGN(ObTableQueryAndMutateP);
private:
common::ObArenaAllocator allocator_;
table::ObTableEntityFactory<table::ObTableEntity> default_entity_factory_;
ObTableServiceQueryCtx query_ctx_;
table::ObTableQueryResult one_result_;
};
} // end namespace observer
} // end namespace oceanbase
#endif /* _OB_TABLE_QUERY_AND_MUTATE_PROCESSOR_H */

View File

@ -49,7 +49,8 @@ int ObTableQueryP::check_arg()
if (!arg_.query_.is_valid()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid table query request", K(ret), "query", arg_.query_);
} else if (arg_.consistency_level_ != ObTableConsistencyLevel::STRONG) {
} else if (!(arg_.consistency_level_ == ObTableConsistencyLevel::STRONG ||
arg_.consistency_level_ == ObTableConsistencyLevel::EVENTUAL)) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("some options not supported yet", K(ret),
"consistency_level", arg_.consistency_level_);
@ -121,6 +122,7 @@ int ObTableQueryP::try_process()
table::ObBinlogRowImageType::MINIMAL/*ignored*/);
ObSEArray<int64_t, 1> part_ids;
const bool is_readonly = true;
const ObTableConsistencyLevel consistency_level = arg_.consistency_level_;
ObTableQueryResultIterator *result_iterator = nullptr;
int32_t result_count = 0;
if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) {
@ -131,7 +133,7 @@ int ObTableQueryP::try_process()
ret = OB_NOT_SUPPORTED;
LOG_WARN("should have one partition", K(ret), K(part_ids));
} else if (FALSE_IT(table_service_ctx_.param_partition_id() = part_ids.at(0))) {
} else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, table_id, part_ids, timeout_ts))) {
} else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, consistency_level, table_id, part_ids, timeout_ts))) {
LOG_WARN("failed to start readonly transaction", K(ret));
} else if (OB_FAIL(table_service_->execute_query(table_service_ctx_, arg_.query_,
result_, result_iterator))) {
@ -139,6 +141,19 @@ int ObTableQueryP::try_process()
LOG_WARN("failed to execute query", K(ret), K(table_id));
}
} else {
if (arg_.query_.get_htable_filter().is_valid()) {
// hbase model, compress the result packet
ObCompressorType compressor_type = INVALID_COMPRESSOR;
if (OB_FAIL(ObCompressorPool::get_instance().get_compressor_type(
GCONF.tableapi_transport_compress_func, compressor_type))) {
compressor_type = INVALID_COMPRESSOR;
} else if (NONE_COMPRESSOR == compressor_type) {
compressor_type = INVALID_COMPRESSOR;
}
this->set_result_compress_type(compressor_type);
ret = OB_SUCCESS; // reset ret
LOG_DEBUG("[yzfdebug] use compressor", K(compressor_type));
}
// one_result references to result_
ObTableQueryResult *one_result = nullptr;
while (OB_SUCC(ret)) {
@ -182,10 +197,12 @@ int ObTableQueryP::try_process()
LOG_WARN("failed to end trans", K(ret), "rollback", need_rollback_trans);
}
ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret;
// record events
stat_event_type_ = ObTableProccessType::TABLE_API_TABLE_QUERY;// table query
if (arg_.query_.get_htable_filter().is_valid()) {
stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_QUERY; // hbase query
} else {
stat_event_type_ = ObTableProccessType::TABLE_API_TABLE_QUERY;// table query
}
audit_row_count_ = result_row_count_;
#ifndef NDEBUG

View File

@ -19,6 +19,7 @@
#include "sql/session/ob_sql_session_info.h"
#include "lib/stat/ob_diagnose_info.h"
#include "lib/stat/ob_session_stat.h"
#include "ob_htable_utils.h"
#include "sql/ob_sql.h"
#include "share/table/ob_table_rpc_proxy.h"
#include "ob_table_rpc_processor_util.h"
@ -241,7 +242,8 @@ ObTableApiProcessorBase::ObTableApiProcessorBase(const ObGlobalContext &gctx)
request_string_len_(0),
need_retry_in_queue_(false),
retry_count_(0),
did_async_end_trans_(false)
did_async_end_trans_(false),
consistency_level_(ObTableConsistencyLevel::STRONG)
{
need_audit_ = GCONF.enable_sql_audit;
}
@ -418,6 +420,23 @@ int ObTableApiProcessorBase::get_participants(uint64_t table_id, const common::O
return get_participants_optimistic(table_id, part_ids, partition_leaders);
}
int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::StmtType stmt_type,
const ObTableConsistencyLevel consistency_level, uint64_t table_id,
const common::ObIArray<int64_t> &part_ids, int64_t timeout_ts)
{
int ret = OB_SUCCESS;
if ((!is_readonly) && (ObTableConsistencyLevel::EVENTUAL == consistency_level)) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("some options not supported yet", K(ret), K(is_readonly), K(consistency_level));
return ret;
}
set_consistency_level(consistency_level);
ret = start_trans(is_readonly, stmt_type, table_id, part_ids, timeout_ts);
return ret;
}
int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::StmtType stmt_type,
uint64_t table_id, const common::ObIArray<int64_t> &part_ids, int64_t timeout_ts)
{
@ -428,6 +447,13 @@ int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::Stmt
}
const uint64_t tenant_id = credential_.tenant_id_;
const int64_t trans_timeout_ts = timeout_ts;
const int64_t trans_consistency_level = (ObTableConsistencyLevel::STRONG == consistency_level_) ?
transaction::ObTransConsistencyLevel::STRONG :
transaction::ObTransConsistencyLevel::WEAK;
const int32_t trans_consistency_type = (ObTableConsistencyLevel::STRONG == consistency_level_) ?
transaction::ObTransConsistencyType::CURRENT_READ :
transaction::ObTransConsistencyType::BOUNDED_STALENESS_READ;
// 1. start transaction
if (OB_SUCC(ret)) {
transaction::ObStartTransParam start_trans_param;
@ -436,11 +462,11 @@ int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::Stmt
start_trans_param.set_type(transaction::ObTransType::TRANS_USER);
start_trans_param.set_isolation(transaction::ObTransIsolation::READ_COMMITED);
start_trans_param.set_autocommit(true);
// @todo ObTableConsistencyLevel::EVENTUAL
start_trans_param.set_consistency_type(transaction::ObTransConsistencyType::CURRENT_READ);
// By default only statement snapshot semantics,
// If need other semantics, please see ObTransConsistencyType and ObTransReadSnapshotType for reference
// ObSqlTransControl::decide_trans_read_interface_specs() decide the semantic of sql layer
// 设置事务一致性类型
start_trans_param.set_consistency_type(trans_consistency_type);
// 默认只要求语句级别快照
// 如果要控制其他的语义,参见ObTransConsistencyType和ObTransReadSnapshotType定义
// SQL层在ObSqlTransControl::decide_trans_read_interface_specs()来决定语义
start_trans_param.set_read_snapshot_type(transaction::ObTransReadSnapshotType::STATEMENT_SNAPSHOT);
start_trans_param.set_cluster_version(GET_MIN_CLUSTER_VERSION());
@ -468,6 +494,7 @@ int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::Stmt
if (OB_SUCC(ret)) {
transaction::ObStmtDesc &stmt_desc = trans_desc_.get_cur_stmt_desc();
const bool is_sfu = false;
stmt_desc.stmt_tenant_id_ = tenant_id;
stmt_desc.phy_plan_type_ = sql::OB_PHY_PLAN_LOCAL;
stmt_desc.stmt_type_ = stmt_type;
stmt_desc.is_sfu_ = is_sfu;
@ -475,7 +502,7 @@ int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::Stmt
// optimize out stmt_desc.set_sql_id_and_save_trace_id("");
// stmt_desc.set_trans_app_trace_id_str(ObString::make_string(""));
stmt_desc.inner_sql_ = false;
stmt_desc.consistency_level_ = transaction::ObTransConsistencyLevel::STRONG;
stmt_desc.consistency_level_ = trans_consistency_level;
stmt_desc.is_contain_inner_table_ = false;
const int64_t stmt_timeout_ts = trans_timeout_ts;
const bool is_retry_sql = false;
@ -876,6 +903,7 @@ int ObTableApiProcessorBase::process_with_retry(const ObString &credential, cons
template class oceanbase::observer::ObTableRpcProcessor<ObTableRpcProxy::ObRpc<OB_TABLE_API_EXECUTE> >;
template class oceanbase::observer::ObTableRpcProcessor<ObTableRpcProxy::ObRpc<OB_TABLE_API_BATCH_EXECUTE> >;
template class oceanbase::observer::ObTableRpcProcessor<ObTableRpcProxy::ObRpc<OB_TABLE_API_EXECUTE_QUERY> >;
template class oceanbase::observer::ObTableRpcProcessor<ObTableRpcProxy::ObRpc<OB_TABLE_API_QUERY_AND_MUTATE> >;
template<class T>
int ObTableRpcProcessor<T>::deserialize()
@ -989,6 +1017,580 @@ void ObTableRpcProcessor<T>::generate_sql_id()
"TABLEAPI0x%04Xvv%016lX", RpcProcessor::PCODE, checksum);
}
////////////////////////////////////////////////////////////////
ObHTableDeleteExecutor::ObHTableDeleteExecutor(common::ObArenaAllocator &alloc,
uint64_t table_id,
uint64_t partition_id,
int64_t timeout_ts,
ObTableApiProcessorBase *processor,
ObTableService *table_service,
storage::ObPartitionService *part_service)
:table_service_(table_service),
part_service_(part_service),
query_ctx_(alloc),
mutate_ctx_(alloc)
{
query_ctx_.param_table_id() = table_id;
query_ctx_.param_partition_id() = partition_id;
query_ctx_.init_param(timeout_ts, processor, &alloc,
false/*ignored*/, table::ObTableEntityType::ET_HKV,
table::ObBinlogRowImageType::MINIMAL/*ignored*/);
mutate_ctx_.param_table_id() = table_id;
mutate_ctx_.param_partition_id() = partition_id;
mutate_ctx_.init_param(timeout_ts, processor, &alloc,
false/*no affected rows*/, table::ObTableEntityType::ET_HKV,
table::ObBinlogRowImageType::MINIMAL/*hbase cell can use put*/);
mutations_result_.set_entity_factory(&entity_factory_);
}
// @see https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Delete.html
int ObHTableDeleteExecutor::htable_delete(const ObTableBatchOperation &batch_operation, int64_t &affected_rows)
{
int ret = OB_SUCCESS;
affected_rows = 0;
ObHTableFilter &htable_filter = query_.htable_filter();
htable_filter.set_valid(true);
if (OB_FAIL(query_.add_select_column(ObHTableConstants::ROWKEY_CNAME_STR))) {
LOG_WARN("failed to add K", K(ret));
} else if (OB_FAIL(query_.add_select_column(ObHTableConstants::CQ_CNAME_STR))) {
LOG_WARN("failed to add Q", K(ret));
} else if (OB_FAIL(query_.add_select_column(ObHTableConstants::VERSION_CNAME_STR))) {
LOG_WARN("failed to add T", K(ret));
} else if (OB_FAIL(query_.add_select_column(ObHTableConstants::VALUE_CNAME_STR))) {
LOG_WARN("failed to add V", K(ret));
} else {
query_.set_batch(1); // mutate for each row
query_.set_max_result_size(-1);
}
ObObj pk_objs_start[3];
ObObj pk_objs_end[3];
ObNewRange range;
range.start_key_.assign(pk_objs_start, 3);
range.end_key_.assign(pk_objs_end, 3);
range.border_flag_.set_inclusive_start();
range.border_flag_.set_inclusive_end();
const int64_t N = batch_operation.count();
for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) // for each delete
{
const ObTableOperation &del_op = batch_operation.at(i);
const ObITableEntity &entity = del_op.entity();
ObHTableCellEntity3 htable_cell(&entity);
ObString row = htable_cell.get_rowkey();
if (htable_cell.last_get_is_null()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("K is null", K(ret), K(entity));
break;
}
if (0 == i) {
// generate scan range by K
pk_objs_start[0].set_varbinary(row);
pk_objs_start[1].set_min_value();
pk_objs_start[2].set_min_value();
pk_objs_end[0].set_varbinary(row);
pk_objs_end[1].set_max_value();
pk_objs_end[2].set_max_value();
if (OB_FAIL(query_.add_scan_range(range))) {
LOG_WARN("failed to add range", K(ret));
break;
}
}
htable_filter.clear_columns();
ObString qualifier = htable_cell.get_qualifier();
if (htable_cell.last_get_is_null()) {
// delete column family, so we need to scan all qualifier
// wildcard scan
} else if (OB_FAIL(htable_filter.add_column(qualifier))) {
LOG_WARN("failed to add column", K(ret));
break;
}
int64_t timestamp = -htable_cell.get_timestamp(); // negative to get the original value
if (-ObHTableConstants::LATEST_TIMESTAMP == timestamp) { // INT64_MAX
// delete the most recently added cell
htable_filter.set_max_versions(1);
htable_filter.set_time_range(ObHTableConstants::INITIAL_MIN_STAMP, ObHTableConstants::INITIAL_MAX_STAMP);
} else if (timestamp > 0) {
// delete the specific version
htable_filter.set_max_versions(1);
htable_filter.set_timestamp(timestamp);
} else if (ObHTableConstants::LATEST_TIMESTAMP == timestamp) { // -INT64_MAX
// delete all version
htable_filter.set_max_versions(INT32_MAX);
htable_filter.set_time_range(ObHTableConstants::INITIAL_MIN_STAMP, ObHTableConstants::INITIAL_MAX_STAMP);
} else {
// delete all versions less than or equal to the timestamp
htable_filter.set_max_versions(INT32_MAX);
htable_filter.set_time_range(ObHTableConstants::INITIAL_MIN_STAMP, (-timestamp)+1);
}
// execute the query
ObTableQueryResultIterator *result_iterator = nullptr;
ObTableQueryResult *one_result = nullptr;
if (OB_FAIL(execute_query(query_, result_iterator))) {
} else {
ret = result_iterator->get_next_result(one_result);
if (OB_ITER_END == ret) {
// empty
ret = OB_SUCCESS;
} else if (OB_SUCCESS != ret) {
LOG_WARN("failed to query", K(ret));
} else if (OB_ISNULL(one_result)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("one_result is NULL", K(ret));
} else {
if (OB_FAIL(generate_delete_cells(*one_result, entity_factory_, mutations_))) {
LOG_WARN("failed to delete cells", K(ret));
} else if (OB_FAIL(execute_mutation(mutations_, mutations_result_))) {
LOG_WARN("failed to execute mutations", K(ret));
} else {
const int64_t result_num = mutations_result_.count();
affected_rows += result_num;
}
} // end else
}
query_ctx_.reset_query_ctx(part_service_);
mutate_ctx_.reset_get_ctx();
} // end for each delete op
return ret;
}
int ObHTableDeleteExecutor::execute_query(const table::ObTableQuery &query,
ObTableQueryResultIterator *&result_iterator)
{
int ret = OB_SUCCESS;
one_result_.reset();
if (OB_FAIL(table_service_->execute_query(query_ctx_, query,
one_result_, result_iterator))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
LOG_WARN("failed to execute query", K(ret));
}
}
return ret;
}
int ObHTableDeleteExecutor::generate_delete_cells(
ObTableQueryResult &one_row,
table::ObTableEntityFactory<table::ObTableEntity> &entity_factory,
ObTableBatchOperation &mutations_out)
{
int ret = OB_SUCCESS;
mutations_out.reset();
entity_factory.free_and_reuse();
one_row.rewind();
ObObj rk, cq, ts;
ObObj key1, key2, key3;
// delete all the selected key-values
const ObITableEntity *key_value = nullptr;
while (OB_SUCC(ret) && OB_SUCC(one_row.get_next_entity(key_value))) {
// for each cell of the row
ObHTableCellEntity2 cell(key_value);
key1.set_varbinary(cell.get_rowkey()); // K
key2.set_varbinary(cell.get_qualifier()); // Q
key3.set_int(-cell.get_timestamp()); // T
ObITableEntity* new_entity = entity_factory.alloc();
if (NULL == new_entity) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret));
} else if (OB_FAIL(new_entity->add_rowkey_value(key1))) {
} else if (OB_FAIL(new_entity->add_rowkey_value(key2))) {
} else if (OB_FAIL(new_entity->add_rowkey_value(key3))) {
} else if (OB_FAIL(mutations_out.del(*new_entity))) {
LOG_WARN("failed to add delete operation", K(ret));
} else {
LOG_DEBUG("[yzfdebug] delete cell", K(ret), "htable_cell", *new_entity, "kv", *key_value);
}
} // end while
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
}
return ret;
}
int ObHTableDeleteExecutor::execute_mutation(const ObTableBatchOperation &mutations,
ObTableBatchOperationResult &mutations_result)
{
int ret = OB_SUCCESS;
mutations_result.reset();
if (OB_FAIL(table_service_->multi_delete(mutate_ctx_, mutations, mutations_result))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
LOG_WARN("failed to multi_delete", K(ret));
}
}
return ret;
}
////////////////////////////////////////////////////////////////
ObHTablePutExecutor::ObHTablePutExecutor(common::ObArenaAllocator &alloc,
uint64_t table_id,
uint64_t partition_id,
int64_t timeout_ts,
ObTableApiProcessorBase *processor,
ObTableService *table_service,
storage::ObPartitionService *part_service)
:table_service_(table_service),
part_service_(part_service),
mutate_ctx_(alloc)
{
mutate_ctx_.param_table_id() = table_id;
mutate_ctx_.param_partition_id() = partition_id;
mutate_ctx_.init_param(timeout_ts, processor, &alloc,
false/*no affected rows*/, table::ObTableEntityType::ET_HKV,
table::ObBinlogRowImageType::MINIMAL/*hbase cell can use put*/);
mutations_result_.set_entity_factory(&entity_factory_);
}
int ObHTablePutExecutor::htable_put(const ObTableBatchOperation &mutations, int64_t &affected_rows, int64_t now_ms/*=0*/)
{
int ret = OB_SUCCESS;
if (0 == now_ms) {
now_ms = -ObHTableUtils::current_time_millis();
}
//ObString htable_row;
const int64_t N = mutations.count();
for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i)
{
const ObTableOperation &mutation = mutations.at(i);
const ObITableEntity &entity = mutation.entity();
if (ObTableOperationType::INSERT_OR_UPDATE != mutation.type()) { // for insert_or_update only
ret = OB_INVALID_ARGUMENT;
LOG_WARN("htable put should use INSERT_OR_UPDATE", K(ret), K(mutation));
} else if (entity.get_rowkey_size() != 3) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("htable should be with 3 rowkey columns", K(ret), K(entity));
} else {
ObRowkey mutate_rowkey = const_cast<ObITableEntity&>(entity).get_rowkey();
ObObj &hbase_timestamp = const_cast<ObObj&>(mutate_rowkey.get_obj_ptr()[ObHTableConstants::COL_IDX_T]); // column T
ObHTableCellEntity3 htable_cell(&entity);
bool row_is_null = htable_cell.last_get_is_null();
int64_t timestamp = htable_cell.get_timestamp();
bool timestamp_is_null = htable_cell.last_get_is_null();
if (row_is_null || timestamp_is_null) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument for htable put", K(ret), K(row_is_null), K(timestamp_is_null));
} else {
// update timestamp iff LATEST_TIMESTAMP
if (ObHTableConstants::LATEST_TIMESTAMP == timestamp) {
hbase_timestamp.set_int(now_ms);
}
}
}
} // end for
if (OB_SUCC(ret)) {
// do the multi_put
mutations_result_.reset();
affected_rows = 0;
if (OB_FAIL(table_service_->multi_insert_or_update(mutate_ctx_, mutations, mutations_result_))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
LOG_WARN("failed to multi_delete", K(ret));
}
} else {
affected_rows = 1;
}
}
return ret;
}
////////////////////////////////////////////////////////////////
ObHTableIncrementExecutor::ObHTableIncrementExecutor(table::ObTableOperationType::Type type,
common::ObArenaAllocator &alloc,
uint64_t table_id,
uint64_t partition_id,
int64_t timeout_ts,
ObTableApiProcessorBase *processor,
ObTableService *table_service,
storage::ObPartitionService *part_service)
:type_(type),
table_service_(table_service),
part_service_(part_service),
mutate_ctx_(alloc)
{
mutate_ctx_.param_table_id() = table_id;
mutate_ctx_.param_partition_id() = partition_id;
mutate_ctx_.init_param(timeout_ts, processor, &alloc,
false/*no affected rows*/, table::ObTableEntityType::ET_HKV,
table::ObBinlogRowImageType::MINIMAL/*hbase cell can use put*/);
mutations_result_.set_entity_factory(&entity_factory_);
}
class ObHTableIncrementExecutor::ColumnIdxComparator
{
public:
bool operator()(const ColumnIdx &a, const ColumnIdx &b) const
{
return a.first.compare(b.first) < 0;
}
};
int ObHTableIncrementExecutor::sort_qualifier(const table::ObTableBatchOperation &increment)
{
int ret = OB_SUCCESS;
const int64_t N = increment.count();
if (N <= 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("empty increment", K(ret));
}
ObString htable_row;
for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i)
{
const ObTableOperation &mutation = increment.at(i);
const ObITableEntity &entity = mutation.entity();
if (type_ != mutation.type()) { // increment or append
ret = OB_INVALID_ARGUMENT;
LOG_WARN("should use INCREMENT/APPEND", K(ret), K_(type), K(mutation));
} else if (entity.get_rowkey_size() != 3) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("htable should be with 3 rowkey columns", K(ret), K(entity));
} else {
ObHTableCellEntity3 htable_cell(&entity);
ObString row = htable_cell.get_rowkey();
bool row_is_null = htable_cell.last_get_is_null();
ObString qualifier = htable_cell.get_qualifier();
bool qualifier_is_null = htable_cell.last_get_is_null();
(void)htable_cell.get_timestamp();
bool timestamp_is_null = htable_cell.last_get_is_null();
if (row_is_null || timestamp_is_null || qualifier_is_null) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument for htable put", K(ret),
K(row_is_null), K(timestamp_is_null), K(qualifier_is_null));
} else {
if (0 == i) {
htable_row = row; // shallow copy
} else if (htable_row != row) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("rowkey not the same", K(ret), K(row), K(htable_row));
break;
}
if (OB_FAIL(columns_.push_back(std::make_pair(qualifier, i)))) {
LOG_WARN("failed to push back", K(ret));
break;
}
}
}
} // end for
if (OB_SUCC(ret)) {
// sort qualifiers
ColumnIdx *end = &columns_.at(columns_.count()-1);
++end;
std::sort(&columns_.at(0), end, ColumnIdxComparator());
}
if (OB_SUCC(ret)) {
// check duplicated qualifiers
for (int64_t i = 0; OB_SUCCESS == ret && i < N-1; ++i)
{
if (columns_.at(i).first == columns_.at(i+1).first) {
ret = OB_ERR_PARAM_DUPLICATE;
LOG_WARN("duplicated qualifiers", K(ret), "cq", columns_.at(i).first, K(i));
}
} // end for
}
return ret;
}
int ObHTableIncrementExecutor::htable_increment(ObTableQueryResult &row_cells,
const table::ObTableBatchOperation &increment,
int64_t &affected_rows,
table::ObTableQueryResult *results)
{
int ret = OB_SUCCESS;
if (OB_FAIL(sort_qualifier(increment))) {
LOG_WARN("failed to sort qualifier", K(ret));
}
row_cells.rewind();
int64_t now_ms = -ObHTableUtils::current_time_millis();
ObObj rk, cq, ts;
const ObITableEntity *get_value = nullptr;
const int64_t N = increment.count();
for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i)
{
const ObTableOperation &mutation = increment.at(columns_.at(i).second);
const ObITableEntity &kv_entity = mutation.entity();
ObHTableCellEntity3 kv(&kv_entity);
ObString qualifier = kv.get_qualifier();
bool need_write = false;
int64_t delta_int = 0;
ObString delta_str = kv.get_value();
bool value_is_null = kv.last_get_is_null();
if (value_is_null) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("increment value is invalid", K(ret), K(kv_entity));
break;
}
if (type_ == ObTableOperationType::INCREMENT) {
if (OB_FAIL(ObHTableUtils::java_bytes_to_int64(delta_str, delta_int))) {
LOG_WARN("failed to convert bytes to integer", K(ret), K(delta_str));
break;
} else {
need_write = (0 != delta_int);
}
} else { // ObTableOperationType::APPEND
need_write = true; // always apply for APPEND
}
if (nullptr == get_value) {
if (OB_FAIL(row_cells.get_next_entity(get_value))) {
if (OB_ITER_END == ret) {
get_value = nullptr;
ret = OB_SUCCESS;
} else {
LOG_WARN("failed to get next", K(ret));
break;
}
}
}
bool first_write = false;
int64_t orig_ts = -1;
ObString orig_str;
if (nullptr != get_value) {
ObHTableCellEntity2 cell(get_value);
ObString qualifier2 = cell.get_qualifier();
int cmp_ret = ObHTableUtils::compare_qualifier(qualifier, qualifier2);
if (0 == cmp_ret) {
// qualifier exists
orig_str = cell.get_value();
orig_ts = cell.get_timestamp();
if (type_ == ObTableOperationType::INCREMENT) {
int64_t orig_int = 0;
if (OB_FAIL(ObHTableUtils::java_bytes_to_int64(orig_str, orig_int))) {
LOG_WARN("failed to convert bytes to integer", K(ret), K(orig_str));
break;
} else {
delta_int += orig_int;
}
} else { // APPEND
// nothing
}
get_value = nullptr; // next cell
} else {
// qualifier not exist, first write
first_write = true;
}
} else {
// no more cells from get
first_write = true;
}
rk.set_varbinary(kv.get_rowkey()); // K
cq.set_varbinary(qualifier); // Q
// generate timestamp
if (orig_ts >= 0) {
// already exists
ts.set_int(std::min(-orig_ts, now_ms)); // T
} else {
int64_t new_ts = kv.get_timestamp();
if (ObHTableConstants::LATEST_TIMESTAMP == new_ts) {
ts.set_int(now_ms);
} else {
ts.set_int(new_ts);
}
}
// generate V
ObObj value_obj; // V
if (type_ == ObTableOperationType::INCREMENT) {
char* bytes = static_cast<char*>(allocator_.alloc(sizeof(int64_t)));
if (NULL == bytes) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret), KP(bytes));
} else if (OB_FAIL(ObHTableUtils::int64_to_java_bytes(delta_int, bytes))) {
LOG_WARN("failed to convert bytes", K(ret), K(delta_int));
} else {
ObString v(sizeof(int64_t), bytes);
value_obj.set_varbinary(v);
}
} else { // APPEND
if (orig_str.empty()) {
value_obj.set_varbinary(delta_str);
} else {
int32_t total_len = orig_str.length() + delta_str.length();
char* bytes = static_cast<char*>(allocator_.alloc(total_len));
if (NULL == bytes) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret), KP(bytes));
} else {
MEMCPY(bytes, orig_str.ptr(), orig_str.length());
MEMCPY(bytes+orig_str.length(), delta_str.ptr(), delta_str.length());
ObString new_str(total_len, bytes);
value_obj.set_varbinary(new_str);
}
}
}
// generate entity
ObITableEntity* new_entity = nullptr;
if (OB_FAIL(ret)) {
} else if (nullptr == (new_entity = entity_factory_.alloc())) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory", K(ret), KP(new_entity));
} else {
if (OB_FAIL(new_entity->add_rowkey_value(rk))) {
} else if (OB_FAIL(new_entity->add_rowkey_value(cq))) {
} else if (OB_FAIL(new_entity->add_rowkey_value(ts))) {
} else if (OB_FAIL(new_entity->set_property(ObHTableConstants::VALUE_CNAME_STR, value_obj))) {
}
}
if (OB_SUCC(ret) && (need_write || first_write)) {
if (OB_FAIL(mutations_.insert_or_update(*new_entity))) {
LOG_WARN("failed to add put operation", K(ret));
} else {
LOG_DEBUG("[yzfdebug] put cell", K(ret), "new_cell", *new_entity, "kv", kv);
}
} // end if need_write
if (OB_SUCC(ret) && NULL != results) {
// Add to results to get returned to the Client. If null, cilent does not want results.
ret = add_to_results(*results, rk, cq, ts, value_obj);
}
} // end for
if (OB_SUCC(ret) && mutations_.count() > 0) {
// do the multi_put
mutations_result_.reset();
affected_rows = 0;
if (OB_FAIL(table_service_->multi_insert_or_update(mutate_ctx_, mutations_, mutations_result_))) {
if (OB_TRY_LOCK_ROW_CONFLICT != ret) {
LOG_WARN("failed to multi_delete", K(ret));
}
} else {
affected_rows = 1;
}
}
return ret;
}
int ObHTableIncrementExecutor::add_to_results(table::ObTableQueryResult &results,
const ObObj &rk, const ObObj &cq,
const ObObj &ts, const ObObj &value)
{
int ret = OB_SUCCESS;
if (results.get_property_count() <= 0) {
if (OB_FAIL(results.add_property_name(ObHTableConstants::ROWKEY_CNAME_STR))) {
LOG_WARN("failed to copy name", K(ret));
} else if (OB_FAIL(results.add_property_name(ObHTableConstants::CQ_CNAME_STR))) {
LOG_WARN("failed to copy name", K(ret));
} else if (OB_FAIL(results.add_property_name(ObHTableConstants::VERSION_CNAME_STR))) {
LOG_WARN("failed to copy name", K(ret));
} else if (OB_FAIL(results.add_property_name(ObHTableConstants::VALUE_CNAME_STR))) {
LOG_WARN("failed to copy name", K(ret));
}
}
if (OB_SUCC(ret)) {
ObObj objs[4];
objs[0] = rk;
objs[1] = cq;
objs[2] = ts;
int64_t timestamp = 0;
objs[2].get_int(timestamp);
objs[2].set_int(-timestamp); // negate_htable_timestamp
objs[3] = value;
common::ObNewRow row(objs, 4);
if (OB_FAIL(results.add_row(row))) { // deep copy
LOG_WARN("failed to add row to results", K(ret), K(row));
}
}
return ret;
}
bool oceanbase::observer::is_bad_routing_err(const int err)
{
// bad routing check : whether client should refresh location cache

View File

@ -20,6 +20,7 @@
#include "sql/optimizer/ob_table_location.h" // ObTableLocation
#include "ob_table_service.h"
#include "sql/monitor/ob_exec_stat.h"
#include "share/table/ob_table.h"
namespace oceanbase
{
namespace table
@ -28,6 +29,8 @@ class ObTableAPITransCb;
} // end namespace table
namespace observer
{
using namespace oceanbase::table;
class ObGlobalContext;
class ObTableService;
@ -124,7 +127,10 @@ public:
public:
static int init_session();
int check_user_access(const ObString &credential_str);
//@{ transaction control
// transaction control
int start_trans(bool is_readonly, const sql::stmt::StmtType stmt_type,
const ObTableConsistencyLevel consistency_level, uint64_t table_id,
const common::ObIArray<int64_t> &part_ids, int64_t timeout_ts);
int start_trans(bool is_readonly, const sql::stmt::StmtType stmt_type, uint64_t table_id,
const common::ObIArray<int64_t> &part_ids, int64_t timeout_ts);
int end_trans(bool is_rollback, rpc::ObRequest *req, int64_t timeout_ts, bool use_sync = false);
@ -151,6 +157,10 @@ protected:
virtual void save_request_string() = 0;
virtual void generate_sql_id() = 0;
// set trans consistency level
void set_consistency_level(const ObTableConsistencyLevel consistency_level) { consistency_level_ = consistency_level; }
ObTableConsistencyLevel consistency_level() const { return consistency_level_; }
private:
int get_participants(uint64_t table_id, const common::ObIArray<int64_t> &part_ids,
common::ObPartitionLeaderArray &partition_leaders);
@ -189,6 +199,7 @@ private:
//when start_participants executed in the leader replica
transaction::ObPartitionEpochArray part_epoch_list_;
bool did_async_end_trans_;
ObTableConsistencyLevel consistency_level_;
};
template<class T>
@ -214,6 +225,104 @@ protected:
};
class ObHTableDeleteExecutor final
{
public:
ObHTableDeleteExecutor(common::ObArenaAllocator &alloc,
uint64_t table_id,
uint64_t partition_id,
int64_t timeout_ts,
ObTableApiProcessorBase *processor,
ObTableService *table_service,
storage::ObPartitionService *part_service);
~ObHTableDeleteExecutor() {}
// @param affected_rows [out] deleted number of htable cells
int htable_delete(const table::ObTableBatchOperation &delete_op, int64_t &affected_rows);
private:
int execute_query(const table::ObTableQuery &query,
table::ObTableQueryResultIterator *&result_iterator);
int generate_delete_cells(
table::ObTableQueryResult &one_row,
table::ObTableEntityFactory<table::ObTableEntity> &entity_factory,
table::ObTableBatchOperation &mutations_out);
int execute_mutation(const table::ObTableBatchOperation &mutations,
table::ObTableBatchOperationResult &mutations_result);
private:
ObTableService *table_service_;
storage::ObPartitionService *part_service_;
ObTableServiceQueryCtx query_ctx_;
table::ObTableQuery query_;
table::ObTableQueryResult one_result_;
table::ObTableEntityFactory<table::ObTableEntity> entity_factory_;
table::ObTableBatchOperation mutations_;
table::ObTableBatchOperationResult mutations_result_;
ObTableServiceGetCtx mutate_ctx_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObHTableDeleteExecutor);
};
class ObHTablePutExecutor final
{
public:
ObHTablePutExecutor(common::ObArenaAllocator &alloc,
uint64_t table_id,
uint64_t partition_id,
int64_t timeout_ts,
ObTableApiProcessorBase *processor,
ObTableService *table_service,
storage::ObPartitionService *part_service);
~ObHTablePutExecutor() {}
int htable_put(const ObTableBatchOperation &put_op, int64_t &affected_rows, int64_t now_ms = 0);
private:
ObTableService *table_service_;
storage::ObPartitionService *part_service_;
table::ObTableEntityFactory<table::ObTableEntity> entity_factory_;
table::ObTableBatchOperationResult mutations_result_;
ObTableServiceGetCtx mutate_ctx_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObHTablePutExecutor);
};
// executor of Increment and Append
class ObHTableIncrementExecutor final
{
public:
ObHTableIncrementExecutor(table::ObTableOperationType::Type type,
common::ObArenaAllocator &alloc,
uint64_t table_id,
uint64_t partition_id,
int64_t timeout_ts,
ObTableApiProcessorBase *processor,
ObTableService *table_service,
storage::ObPartitionService *part_service);
~ObHTableIncrementExecutor() {}
int htable_increment(ObTableQueryResult &row_cells,
const table::ObTableBatchOperation &increment_op,
int64_t &affected_rows,
table::ObTableQueryResult *results);
private:
typedef std::pair<common::ObString, int32_t> ColumnIdx;
class ColumnIdxComparator;
int sort_qualifier(const table::ObTableBatchOperation &increment);
int execute_mutation(const table::ObTableBatchOperation &mutations,
table::ObTableBatchOperationResult &mutations_result);
static int add_to_results(table::ObTableQueryResult &results, const ObObj &rk, const ObObj &cq,
const ObObj &ts, const ObObj &value);
private:
table::ObTableOperationType::Type type_;
ObTableService *table_service_;
storage::ObPartitionService *part_service_;
table::ObTableEntityFactory<table::ObTableEntity> entity_factory_;
table::ObTableBatchOperation mutations_;
table::ObTableBatchOperationResult mutations_result_;
ObTableServiceGetCtx mutate_ctx_;
common::ObSEArray<ColumnIdx, OB_DEFAULT_SE_ARRAY_COUNT> columns_;
common::ObArenaAllocator allocator_;
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObHTableIncrementExecutor);
};
template<class T>
int64_t ObTableRpcProcessor<T>::get_timeout_ts() const

View File

@ -45,6 +45,15 @@ enum ObTableProccessType
TABLE_API_BATCH_RETRIVE,
TABLE_API_BATCH_HYBRID,
// hbase mutate
TABLE_API_HBASE_DELETE,
TABLE_API_HBASE_PUT,
TABLE_API_HBASE_CHECK_AND_DELETE,
TABLE_API_HBASE_CHECK_AND_PUT,
TABLE_API_HBASE_INCREMENT,
TABLE_API_HBASE_APPEND,
TABLE_API_HBASE_HYBRID,
// query
TABLE_API_TABLE_QUERY,
TABLE_API_HBASE_QUERY,
@ -171,6 +180,49 @@ public:
EVENT_ADD(TABLEAPI_BATCH_HYBRID_INSERT_OR_UPDATE_ROW, rows); // @todo row count for each type
SET_AUDIT_SQL_STRING(batch_hybrid);
break;
// hbase mutate
case ObTableProccessType::TABLE_API_HBASE_DELETE:
EVENT_INC(HBASEAPI_DELETE_COUNT);
EVENT_ADD(HBASEAPI_DELETE_TIME, elapsed_us);
EVENT_ADD(HBASEAPI_DELETE_ROW, rows);
SET_AUDIT_SQL_STRING(hbase_delete);
break;
case ObTableProccessType::TABLE_API_HBASE_PUT:
EVENT_INC(HBASEAPI_PUT_COUNT);
EVENT_ADD(HBASEAPI_PUT_TIME, elapsed_us);
EVENT_ADD(HBASEAPI_PUT_ROW, rows);
SET_AUDIT_SQL_STRING(hbase_put);
break;
case ObTableProccessType::TABLE_API_HBASE_CHECK_AND_DELETE:
EVENT_INC(HBASEAPI_CHECK_DELETE_COUNT);
EVENT_ADD(HBASEAPI_CHECK_DELETE_TIME, elapsed_us);
EVENT_ADD(HBASEAPI_CHECK_DELETE_ROW, rows);
SET_AUDIT_SQL_STRING(hbase_check_and_delete);
break;
case ObTableProccessType::TABLE_API_HBASE_CHECK_AND_PUT:
EVENT_INC(HBASEAPI_CHECK_PUT_COUNT);
EVENT_ADD(HBASEAPI_CHECK_PUT_TIME, elapsed_us);
EVENT_ADD(HBASEAPI_CHECK_PUT_ROW, rows);
SET_AUDIT_SQL_STRING(hbase_check_and_put);
break;
case ObTableProccessType::TABLE_API_HBASE_INCREMENT:
EVENT_INC(HBASEAPI_INCREMENT_COUNT);
EVENT_ADD(HBASEAPI_INCREMENT_TIME, elapsed_us);
EVENT_ADD(HBASEAPI_INCREMENT_ROW, rows);
SET_AUDIT_SQL_STRING(hbase_increment);
break;
case ObTableProccessType::TABLE_API_HBASE_APPEND:
EVENT_INC(HBASEAPI_APPEND_COUNT);
EVENT_ADD(HBASEAPI_APPEND_TIME, elapsed_us);
EVENT_ADD(HBASEAPI_APPEND_ROW, rows);
SET_AUDIT_SQL_STRING(hbase_append);
break;
case ObTableProccessType::TABLE_API_HBASE_HYBRID:
EVENT_INC(HBASEAPI_HYBRID_COUNT);
EVENT_ADD(HBASEAPI_HYBRID_TIME, elapsed_us);
EVENT_ADD(HBASEAPI_HYBRID_ROW, rows);
SET_AUDIT_SQL_STRING(hbase_hybrid);
break;
// table query
case ObTableProccessType::TABLE_API_TABLE_QUERY:
EVENT_INC(TABLEAPI_QUERY_COUNT);
@ -178,6 +230,13 @@ public:
EVENT_ADD(TABLEAPI_QUERY_ROW, rows);
SET_AUDIT_SQL_STRING(table_query);
break;
// hbase query
case ObTableProccessType::TABLE_API_HBASE_QUERY:
EVENT_INC(HBASEAPI_SCAN_COUNT);
EVENT_ADD(HBASEAPI_SCAN_TIME, elapsed_us);
EVENT_ADD(HBASEAPI_SCAN_ROW, rows);
SET_AUDIT_SQL_STRING(hbase_scan);
break;
default:
SET_AUDIT_SQL_STRING(unknown);

View File

@ -19,6 +19,7 @@
#include "sql/engine/expr/ob_expr_res_type.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
#include "lib/thread_local/ob_tsi_factory.h"
#include "ob_htable_filter_operator.h"
#include "sql/engine/expr/ob_expr_add.h"
using namespace oceanbase::observer;
using namespace oceanbase::common;
@ -199,12 +200,15 @@ int ObTableService::check_column_type(const ObExprResType &column_type, ObObj &o
return ret;
}
int ObTableService::insert_or_update_can_use_put(uint64_t table_id, const ObITableEntity &entity, bool &use_put)
int ObTableService::insert_or_update_can_use_put(ObTableEntityType entity_type, uint64_t table_id, const ObITableEntity &entity, bool &use_put)
{
int ret = OB_SUCCESS;
schema::ObSchemaGetterGuard schema_guard;
const schema::ObTableSchema *table_schema = NULL;
if (OB_FAIL(schema_service_->get_schema_guard(schema_guard))) {
if (ObTableEntityType::ET_HKV == entity_type) {
// hbase model table does not have secondary index and always specify all the properties (column V)
use_put = true;
} else if (OB_FAIL(schema_service_->get_schema_guard(schema_guard))) {
LOG_WARN("failed to get schema guard", K(ret));
} else if (OB_FAIL(schema_guard.get_table_schema(table_id, table_schema))) {
LOG_WARN("get table schema failed", K(table_id), K(ret));
@ -252,7 +256,7 @@ int ObTableService::execute_insert_or_update(ObTableServiceGetCtx &ctx, const Ob
int ret = OB_SUCCESS;
const ObITableEntity &entity = table_operation.entity();
bool can_use_put = true;
if (OB_FAIL(insert_or_update_can_use_put(ctx.param_.table_id_, entity, can_use_put))) {
if (OB_FAIL(insert_or_update_can_use_put(ctx.param_.entity_type_, ctx.param_.table_id_, entity, can_use_put))) {
LOG_WARN("failed to check", K(ret));
} else if (can_use_put
&& ctx.param_.binlog_row_image_type_ != ObBinlogRowImageType::FULL) {
@ -386,7 +390,8 @@ int ObTableService::multi_insert_or_update(ObTableServiceGetCtx &ctx,
int ret = OB_SUCCESS;
const ObTableOperation &one_op = batch_operation.at(0);
bool can_use_put = true;
if (OB_FAIL(insert_or_update_can_use_put(ctx.param_.table_id_, one_op.entity(), can_use_put))) {
if (OB_FAIL(insert_or_update_can_use_put(ctx.param_.entity_type_,
ctx.param_.table_id_, one_op.entity(), can_use_put))) {
LOG_WARN("failed to check", K(ret));
} else if (can_use_put
&& ctx.param_.binlog_row_image_type_ != ObBinlogRowImageType::FULL) {
@ -744,12 +749,15 @@ int ObTableService::add_index_columns_if_missing(schema::ObSchemaGetterGuard &sc
return ret;
}
int ObTableService::delete_can_use_put(uint64_t table_id, bool &use_put)
int ObTableService::delete_can_use_put(table::ObTableEntityType entity_type, uint64_t table_id, bool &use_put)
{
int ret = OB_SUCCESS;
schema::ObSchemaGetterGuard schema_guard;
const schema::ObTableSchema *table_schema = NULL;
if (OB_FAIL(schema_service_->get_schema_guard(schema_guard))) {
if (entity_type == ObTableEntityType::ET_HKV) {
// hbase model table does not have secondary index
use_put = true;
} else if (OB_FAIL(schema_service_->get_schema_guard(schema_guard))) {
LOG_WARN("failed to get schema guard", K(ret));
} else if (OB_FAIL(schema_guard.get_table_schema(table_id, table_schema))) {
LOG_WARN("get table schema failed", K(table_id), K(ret));
@ -1725,7 +1733,8 @@ int ObTableService::fill_query_table_param(uint64_t table_id,
common::ObIArray<sql::ObExprResType> &rowkey_columns_type,
int64_t &schema_version,
uint64_t &index_id,
int64_t &padding_num)
int64_t &padding_num,
table::ObHColumnDescriptor *hcolumn_desc)
{
int ret = OB_SUCCESS;
schema::ObSchemaGetterGuard schema_guard;
@ -1754,8 +1763,16 @@ int ObTableService::fill_query_table_param(uint64_t table_id,
} else if (OB_FAIL(table_param.convert(*table_schema, ((NULL == index_schema) ? *table_schema: *index_schema),
output_column_ids, index_back))) {
LOG_WARN("failed to convert table param", K(ret));
} else {
//do nothing
} else if (!table_schema->get_comment_str().empty()
&& NULL != hcolumn_desc) {
if (OB_FAIL(hcolumn_desc->from_string(table_schema->get_comment_str()))) {
LOG_WARN("failed to parse hcolumn_desc from comment string", K(ret),
"comment", table_schema->get_comment_str());
} else {
LOG_DEBUG("[yzfdebug] get ttl", K(table_id),
"comment", table_schema->get_comment_str(),
"ttl", hcolumn_desc->get_time_to_live());
}
}
}
return ret;
@ -1986,12 +2003,28 @@ ObNormalTableQueryResultIterator *ObTableServiceQueryCtx::get_normal_result_iter
return normal_result_iterator_;
}
ObHTableFilterOperator *ObTableServiceQueryCtx::get_htable_result_iterator(
const ObTableQuery &query, table::ObTableQueryResult &one_result)
{
if (NULL == htable_result_iterator_) {
htable_result_iterator_ = OB_NEWx(ObHTableFilterOperator, param_.allocator_, query, one_result);
if (NULL == htable_result_iterator_) {
LOG_WARN("failed to allocate htable filter");
}
}
return htable_result_iterator_;
}
void ObTableServiceQueryCtx::destroy_result_iterator(storage::ObPartitionService *part_service)
{
if (NULL != normal_result_iterator_) {
normal_result_iterator_->~ObNormalTableQueryResultIterator();
normal_result_iterator_ = NULL;
}
if (NULL != htable_result_iterator_) {
htable_result_iterator_->~ObHTableFilterOperator();
htable_result_iterator_ = NULL;
}
if (NULL != scan_result_) {
if (NULL == part_service) {
LOG_ERROR("part_service is NULL, memory leak");
@ -2002,6 +2035,43 @@ void ObTableServiceQueryCtx::destroy_result_iterator(storage::ObPartitionService
}
}
int ObTableService::check_htable_query_args(const ObTableQuery &query)
{
int ret = OB_SUCCESS;
const ObIArray<ObString> &select_columns = query.get_select_columns();
int64_t N = select_columns.count();
if (N != 4) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("TableQuery with htable_filter should select 4 columns", K(ret), K(N));
}
if (OB_SUCC(ret)) {
if (ObHTableConstants::ROWKEY_CNAME_STR != select_columns.at(0)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("TableQuery with htable_filter should select K as the first column", K(ret), K(select_columns));
} else if (ObHTableConstants::CQ_CNAME_STR != select_columns.at(1)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("TableQuery with htable_filter should select Q as the second column", K(ret), K(select_columns));
} else if (ObHTableConstants::VERSION_CNAME_STR != select_columns.at(2)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("TableQuery with htable_filter should select T as the third column", K(ret), K(select_columns));
} else if (ObHTableConstants::VALUE_CNAME_STR != select_columns.at(3)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("TableQuery with htable_filter should select V as the fourth column", K(ret), K(select_columns));
}
}
if (OB_SUCC(ret)) {
if (0 != query.get_offset()
|| -1 != query.get_limit()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("htable scan should not set Offset and Limit", K(ret), K(query));
} else if (ObQueryFlag::Forward != query.get_scan_order() && ObQueryFlag::Reverse != query.get_scan_order()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("TableQuery with htable_filter only support forward and reverse scan yet", K(ret));
}
}
return ret;
}
int ObTableService::execute_query(ObTableServiceQueryCtx &ctx, const ObTableQuery &query,
table::ObTableQueryResult &one_result,
table::ObTableQueryResultIterator *&query_result)
@ -2014,16 +2084,33 @@ int ObTableService::execute_query(ObTableServiceQueryCtx &ctx, const ObTableQuer
uint64_t index_id = OB_INVALID_ID;
int64_t padding_num = 0;
if (NULL == (query_result = ctx.get_normal_result_iterator(query, one_result))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate result iterator", K(ret));
ObHColumnDescriptor hcolumn_desc;
ObHColumnDescriptor *p_hcolumn_desc = NULL;
if (query.get_htable_filter().is_valid()) {
if (OB_FAIL(check_htable_query_args(query))) {
LOG_WARN("invalid query request", K(ret));
} else if (NULL == (query_result = ctx.get_htable_result_iterator(query, one_result))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate htable result iterator", K(ret));
} else if (OB_FAIL(ctx.htable_result_iterator_->parse_filter_string(ctx.param_.allocator_))) {
LOG_WARN("failed to parse htable filter string", K(ret));
} else {
p_hcolumn_desc = &hcolumn_desc;
}
} else {
if (NULL == (query_result = ctx.get_normal_result_iterator(query, one_result))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate result iterator", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(fill_query_table_param(table_id, query.get_select_columns(),
query.get_index_name(),
*(ctx.table_param_), output_column_ids,
ctx.columns_type_, schema_version,
index_id, padding_num))) { // @todo optimize, table_param_ can be cached
index_id, padding_num,
p_hcolumn_desc))) { // @todo optimize, table_param_ can be cached
LOG_WARN("failed to fill param", K(ret));
} else if (OB_FAIL(fill_query_scan_ranges(ctx, query,
(table_id != index_id) ? padding_num : -1,
@ -2038,7 +2125,14 @@ int ObTableService::execute_query(ObTableServiceQueryCtx &ctx, const ObTableQuer
LOG_WARN("fail to scan table", K(ret));
}
} else {
ctx.normal_result_iterator_->set_scan_result(ctx.scan_result_);
if (query.get_htable_filter().is_valid()) {
ctx.htable_result_iterator_->set_scan_result(ctx.scan_result_);
if (p_hcolumn_desc->get_time_to_live() > 0) {
ctx.htable_result_iterator_->set_ttl(p_hcolumn_desc->get_time_to_live());
}
} else {
ctx.normal_result_iterator_->set_scan_result(ctx.scan_result_);
}
}
return ret;
}

View File

@ -20,6 +20,11 @@
#include "share/schema/ob_table_param.h"
namespace oceanbase
{
namespace table
{
class ObHTableFilterOperator;
class ObHColumnDescriptor;
} // end namespace table
namespace storage
{
class ObPartitionService;
@ -151,10 +156,12 @@ struct ObTableServiceQueryCtx: public ObTableServiceGetCtx
{
public:
ObNormalTableQueryResultIterator *normal_result_iterator_;
table::ObHTableFilterOperator *htable_result_iterator_;
public:
ObTableServiceQueryCtx(common::ObArenaAllocator &alloc)
:ObTableServiceGetCtx(alloc),
normal_result_iterator_(NULL)
normal_result_iterator_(NULL),
htable_result_iterator_(NULL)
{}
void reset_query_ctx(storage::ObPartitionService *part_service)
{
@ -163,6 +170,8 @@ public:
}
ObNormalTableQueryResultIterator *get_normal_result_iterator(const ObTableQuery &query,
table::ObTableQueryResult &one_result);
table::ObHTableFilterOperator *get_htable_result_iterator(const ObTableQuery &query,
table::ObTableQueryResult &one_result);
void destroy_result_iterator(storage::ObPartitionService *part_service);
};
@ -215,7 +224,7 @@ private:
common::ObIArray<uint64_t> &column_ids,
common::ObIArray<sql::ObExprResType> *columns_type);
int insert_or_update_can_use_put(uint64_t table_id, const table::ObITableEntity &entity, bool &use_put);
int insert_or_update_can_use_put(table::ObTableEntityType entity_type, uint64_t table_id, const table::ObITableEntity &entity, bool &use_put);
int add_one_result(ObTableBatchOperationResult &result,
table::ObTableOperationType::Type op_type,
int32_t error_code,
@ -242,7 +251,7 @@ private:
const ObTableBatchOperation &batch_operation,
ObTableApiRowIterator *scan_result,
ObTableBatchOperationResult &result);
int delete_can_use_put(uint64_t table_id, bool &use_put);
int delete_can_use_put(table::ObTableEntityType entity_type, uint64_t table_id, bool &use_put);
static int cons_all_index_properties(share::schema::ObSchemaGetterGuard &schema_guard,
const share::schema::ObTableSchema &table_schema,
common::ObIArray<uint64_t> &column_ids,
@ -282,7 +291,8 @@ private:
common::ObIArray<sql::ObExprResType> &rowkey_columns_type,
int64_t &schema_version,
uint64_t &index_id,
int64_t &padding_num);
int64_t &padding_num,
table::ObHColumnDescriptor *hcolumn_desc);
int fill_query_scan_ranges(ObTableServiceCtx &ctx,
const ObTableQuery &query,
int64_t padding_num,
@ -295,6 +305,7 @@ private:
int32_t limit,
int32_t offset,
storage::ObTableScanParam &scan_param);
int check_htable_query_args(const ObTableQuery &query);
private:
int fill_new_entity(
bool returning_rowkey,

View File

@ -904,6 +904,7 @@ void ObTableQuery::reset()
index_name_.reset();
batch_size_ = -1;
max_result_size_ = -1;
htable_filter_.reset();
}
bool ObTableQuery::is_valid() const
@ -1021,6 +1022,10 @@ uint64_t ObTableQuery::get_checksum() const
checksum = ob_crc64(checksum, index_name_.ptr(), index_name_.length());
checksum = ob_crc64(checksum, &batch_size_, sizeof(batch_size_));
checksum = ob_crc64(checksum, &max_result_size_, sizeof(max_result_size_));
if (htable_filter_.is_valid()) {
const uint64_t htable_filter_checksum = htable_filter_.get_checksum();
checksum = ob_crc64(checksum, &htable_filter_checksum, sizeof(htable_filter_checksum));
}
return checksum;
}
@ -1033,7 +1038,8 @@ OB_UNIS_DEF_SERIALIZE(ObTableQuery,
scan_order_,
index_name_,
batch_size_,
max_result_size_);
max_result_size_,
htable_filter_);
OB_UNIS_DEF_SERIALIZE_SIZE(ObTableQuery,
key_ranges_,
@ -1044,7 +1050,8 @@ OB_UNIS_DEF_SERIALIZE_SIZE(ObTableQuery,
scan_order_,
index_name_,
batch_size_,
max_result_size_);
max_result_size_,
htable_filter_);
OB_DEF_DESERIALIZE(ObTableQuery,)
{
@ -1085,7 +1092,8 @@ OB_DEF_DESERIALIZE(ObTableQuery,)
scan_order_,
index_name_,
batch_size_,
max_result_size_
max_result_size_,
htable_filter_
);
}
return ret;
@ -1095,6 +1103,144 @@ OB_DEF_DESERIALIZE(ObTableQuery,)
ObTableEntityIterator::~ObTableEntityIterator()
{}
////////////////////////////////////////////////////////////////
const char* const ObHTableConstants::ROWKEY_CNAME = "K";
const char* const ObHTableConstants::CQ_CNAME = "Q";
const char* const ObHTableConstants::VERSION_CNAME = "T";
const char* const ObHTableConstants::VALUE_CNAME = "V";
const ObString ObHTableConstants::ROWKEY_CNAME_STR = ObString::make_string(ROWKEY_CNAME);
const ObString ObHTableConstants::CQ_CNAME_STR = ObString::make_string(CQ_CNAME);
const ObString ObHTableConstants::VERSION_CNAME_STR = ObString::make_string(VERSION_CNAME);
const ObString ObHTableConstants::VALUE_CNAME_STR = ObString::make_string(VALUE_CNAME);
ObHTableFilter::ObHTableFilter()
:is_valid_(false),
select_column_qualifier_(),
min_stamp_(ObHTableConstants::INITIAL_MIN_STAMP),
max_stamp_(ObHTableConstants::INITIAL_MAX_STAMP),
max_versions_(1),
limit_per_row_per_cf_(-1),
offset_per_row_per_cf_(0),
filter_string_()
{}
void ObHTableFilter::reset()
{
is_valid_ = false;
select_column_qualifier_.reset();
min_stamp_ = ObHTableConstants::INITIAL_MIN_STAMP;
max_stamp_ = ObHTableConstants::INITIAL_MAX_STAMP;
max_versions_ = 1;
limit_per_row_per_cf_ = -1;
offset_per_row_per_cf_ = 0;
filter_string_.reset();
}
int ObHTableFilter::add_column(const ObString &qualifier)
{
int ret = OB_SUCCESS;
const int64_t N = select_column_qualifier_.count();
for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i)
{
if (0 == select_column_qualifier_.at(i).case_compare(qualifier)) {
ret = OB_ERR_COLUMN_DUPLICATE;
LOG_WARN("column already exists", K(ret), K(qualifier));
break;
}
} // end for
if (OB_SUCC(ret)) {
if (OB_FAIL(select_column_qualifier_.push_back(qualifier))) {
LOG_WARN("failed to push back", K(ret));
}
}
return ret;
}
int ObHTableFilter::set_time_range(int64_t min_stamp, int64_t max_stamp)
{
int ret = OB_SUCCESS;
if (min_stamp >= max_stamp || min_stamp_ < 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid time range", K(ret), K(min_stamp), K(max_stamp));
} else {
min_stamp_ = min_stamp;
max_stamp_ = max_stamp;
}
return ret;
}
int ObHTableFilter::set_max_versions(int32_t versions)
{
int ret = OB_SUCCESS;
if (versions <= 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid max versions", K(ret), K(versions));
} else {
max_versions_ = versions;
}
return ret;
}
int ObHTableFilter::set_max_results_per_column_family(int32_t limit)
{
int ret = OB_SUCCESS;
if (limit < -1 || 0 == limit) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("limit cannot be negative or zero", K(ret), K(limit));
} else {
limit_per_row_per_cf_ = limit;
}
return ret;
}
int ObHTableFilter::set_row_offset_per_column_family(int32_t offset)
{
int ret = OB_SUCCESS;
if (offset < 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("offset cannot be negative", K(ret), K(offset));
} else {
offset_per_row_per_cf_ = offset;
}
return ret;
}
int ObHTableFilter::set_filter(const ObString &filter)
{
filter_string_ = filter;
return OB_SUCCESS;
}
uint64_t ObHTableFilter::get_checksum() const
{
uint64_t checksum = 0;
for (int64_t i = 0; i < select_column_qualifier_.count(); ++i) {
const ObString &cur_qualifier = select_column_qualifier_.at(i);
checksum = ob_crc64(checksum, cur_qualifier.ptr(), cur_qualifier.length());
}
checksum = ob_crc64(checksum, &min_stamp_, sizeof(min_stamp_));
checksum = ob_crc64(checksum, &max_stamp_, sizeof(max_stamp_));
checksum = ob_crc64(checksum, &max_versions_, sizeof(max_versions_));
checksum = ob_crc64(checksum, &limit_per_row_per_cf_, sizeof(limit_per_row_per_cf_));
checksum = ob_crc64(checksum, &offset_per_row_per_cf_, sizeof(offset_per_row_per_cf_));
checksum = ob_crc64(checksum, filter_string_.ptr(), filter_string_.length());
return checksum;
}
// If valid_ is true, serialize the members. Otherwise, nothing/dummy is serialized.
OB_SERIALIZE_MEMBER_IF(ObHTableFilter,
(true == is_valid_),
is_valid_,
select_column_qualifier_,
min_stamp_,
max_stamp_,
max_versions_,
limit_per_row_per_cf_,
offset_per_row_per_cf_,
filter_string_);
////////////////////////////////////////////////////////////////
ObTableQueryResult::ObTableQueryResult()
:row_count_(0),
@ -1379,3 +1525,24 @@ OB_DEF_DESERIALIZE(ObTableQueryResult)
}
return ret;
}
////////////////////////////////////////////////////////////////
uint64_t ObTableQueryAndMutate::get_checksum()
{
uint64_t checksum = 0;
const uint64_t query_checksum = query_.get_checksum();
const uint64_t mutation_checksum = mutations_.get_checksum();
checksum = ob_crc64(checksum, &query_checksum, sizeof(query_checksum));
checksum = ob_crc64(checksum, &mutation_checksum, sizeof(mutation_checksum));
checksum = ob_crc64(checksum, &return_affected_entity_, sizeof(return_affected_entity_));
return checksum;
}
OB_SERIALIZE_MEMBER(ObTableQueryAndMutate,
query_,
mutations_);
OB_SERIALIZE_MEMBER(ObTableQueryAndMutateResult,
affected_rows_,
affected_entity_);

View File

@ -131,7 +131,8 @@ private:
enum class ObTableEntityType
{
ET_DYNAMIC = 0,
ET_KV = 1
ET_KV = 1,
ET_HKV = 2
};
// @note not thread-safe
@ -517,6 +518,94 @@ private:
common::ObIAllocator *alloc_;
};
class ObHTableConstants
{
public:
static constexpr int64_t LATEST_TIMESTAMP = -INT64_MAX;
static constexpr int64_t OLDEST_TIMESTAMP = INT64_MAX;
static constexpr int64_t INITIAL_MIN_STAMP = 0;
static constexpr int64_t INITIAL_MAX_STAMP = INT64_MAX;
static const char* const ROWKEY_CNAME;
static const char* const CQ_CNAME;
static const char* const VERSION_CNAME;
static const char* const VALUE_CNAME;
static const ObString ROWKEY_CNAME_STR;
static const ObString CQ_CNAME_STR;
static const ObString VERSION_CNAME_STR;
static const ObString VALUE_CNAME_STR;
// create table t1$cf1 (K varbinary(1024), Q varchar(256), T bigint, V varbinary(1024), primary key(K, Q, T));
static const int64_t COL_IDX_K = 0;
static const int64_t COL_IDX_Q = 1;
static const int64_t COL_IDX_T = 2;
static const int64_t COL_IDX_V = 3;
private:
ObHTableConstants() = delete;
};
/// special filter for HTable
class ObHTableFilter final
{
OB_UNIS_VERSION(1);
public:
ObHTableFilter();
~ObHTableFilter() = default;
void reset();
void set_valid(bool valid) { is_valid_ = valid; }
bool is_valid() const { return is_valid_; }
/// Get the column with the specified qualifier.
int add_column(const ObString &qualifier);
/// Get versions of columns with the specified timestamp.
int set_timestamp(int64_t timestamp) { min_stamp_ = timestamp; max_stamp_ = timestamp + 1; return common::OB_SUCCESS; }
/// Get versions of columns only within the specified timestamp range, [minStamp, maxStamp).
int set_time_range(int64_t min_stamp, int64_t max_stamp);
/// Get up to the specified number of versions of each column.
int set_max_versions(int32_t versions);
/// Set the maximum number of values to return per row per Column Family
/// @param limit - the maximum number of values returned / row / CF
int set_max_results_per_column_family(int32_t limit);
/// Set offset for the row per Column Family.
/// @param offset - is the number of kvs that will be skipped.
int set_row_offset_per_column_family(int32_t offset);
/// Apply the specified server-side filter when performing the Query.
/// @param filter - a file string using the hbase filter language
/// @see the filter language at https://issues.apache.org/jira/browse/HBASE-4176
int set_filter(const ObString &filter);
const ObIArray<ObString> &get_columns() const { return select_column_qualifier_; }
bool with_latest_timestamp() const { return with_all_time() && 1 == max_versions_; }
bool with_timestamp() const { return min_stamp_ == max_stamp_ && min_stamp_ >= 0; }
bool with_all_time() const { return ObHTableConstants::INITIAL_MIN_STAMP == min_stamp_ && ObHTableConstants::INITIAL_MAX_STAMP == max_stamp_; }
int64_t get_min_stamp() const { return min_stamp_; }
int64_t get_max_stamp() const { return max_stamp_; }
int32_t get_max_versions() const { return max_versions_; }
int32_t get_max_results_per_column_family() const { return limit_per_row_per_cf_; }
int32_t get_row_offset_per_column_family() const { return offset_per_row_per_cf_; }
const ObString &get_filter() const { return filter_string_; }
void clear_columns() { select_column_qualifier_.reset(); }
uint64_t get_checksum() const;
TO_STRING_KV(K_(is_valid),
"column_qualifier", select_column_qualifier_,
K_(min_stamp),
K_(max_stamp),
K_(max_versions),
K_(limit_per_row_per_cf),
K_(offset_per_row_per_cf),
K_(filter_string));
private:
bool is_valid_;
ObSEArray<ObString, 16> select_column_qualifier_;
int64_t min_stamp_; // default -1
int64_t max_stamp_; // default -1
int32_t max_versions_; // default 1
int32_t limit_per_row_per_cf_; // default -1 means unlimited
int32_t offset_per_row_per_cf_; // default 0
ObString filter_string_;
};
/// A table query
/// 1. support multi range scan
/// 2. support reverse scan
@ -535,7 +624,8 @@ public:
scan_order_(common::ObQueryFlag::Forward),
index_name_(),
batch_size_(-1),
max_result_size_(-1)
max_result_size_(-1),
htable_filter_()
{}
~ObTableQuery() = default;
void reset();
@ -556,6 +646,8 @@ public:
int set_offset(int32_t offset);
/// Add filter, currently NOT supported.
int set_filter(const ObString &filter);
/// Add filter only for htable.
ObHTableFilter& htable_filter() { return htable_filter_; }
/// Set max row count of each batch.
/// For htable, set the maximum number of cells to return for each call to next().
int set_batch(int32_t batch_size);
@ -570,6 +662,7 @@ public:
int32_t get_offset() const { return offset_; }
common::ObQueryFlag::ScanOrder get_scan_order() const { return scan_order_; }
const ObString &get_index_name() const { return index_name_; }
const ObHTableFilter& get_htable_filter() const { return htable_filter_; }
int32_t get_batch() const { return batch_size_; }
int64_t get_max_result_size() const { return max_result_size_; }
int64_t get_range_count() const { return key_ranges_.count(); }
@ -584,6 +677,7 @@ public:
K_(offset),
K_(scan_order),
K_(index_name),
K_(htable_filter),
K_(batch_size),
K_(max_result_size));
public:
@ -601,6 +695,7 @@ private:
ObString index_name_;
int32_t batch_size_;
int64_t max_result_size_;
ObHTableFilter htable_filter_;
};
/// result for ObTableQuery
@ -616,6 +711,42 @@ public:
virtual int get_next_entity(const ObITableEntity *&entity) = 0;
};
/// query and mutate the selected rows.
class ObTableQueryAndMutate final
{
OB_UNIS_VERSION(1);
public:
ObTableQueryAndMutate()
:return_affected_entity_(true)
{}
const ObTableQuery &get_query() const { return query_; }
ObTableQuery &get_query() { return query_; }
const ObTableBatchOperation &get_mutations() const { return mutations_; }
ObTableBatchOperation &get_mutations() { return mutations_; }
bool return_affected_entity() const { return return_affected_entity_; }
void set_deserialize_allocator(common::ObIAllocator *allocator);
void set_entity_factory(ObITableEntityFactory *entity_factory);
uint64_t get_checksum();
TO_STRING_KV(K_(query),
K_(mutations));
private:
ObTableQuery query_;
ObTableBatchOperation mutations_;
bool return_affected_entity_;
};
inline void ObTableQueryAndMutate::set_deserialize_allocator(common::ObIAllocator *allocator)
{
query_.set_deserialize_allocator(allocator);
}
inline void ObTableQueryAndMutate::set_entity_factory(ObITableEntityFactory *entity_factory)
{
mutations_.set_entity_factory(entity_factory);
}
class ObTableQueryResult: public ObTableEntityIterator
{
OB_UNIS_VERSION(1);
@ -651,6 +782,20 @@ private:
ObTableEntity curr_entity_;
};
class ObTableQueryAndMutateResult final
{
OB_UNIS_VERSION(1);
public:
TO_STRING_KV(K_(affected_rows));
public:
int64_t affected_rows_;
// If return_affected_entity_ in ObTableQueryAndMutate is set, then return the respond entity.
// In the case of delete and insert_or_update, return the old rows before modified.
// In the case of increment and append, return the new rows after modified.
ObTableQueryResult affected_entity_;
};
} // end namespace table
} // end namespace oceanbase

View File

@ -29,6 +29,7 @@ public:
RPC_S(PR5 execute, obrpc::OB_TABLE_API_EXECUTE, (table::ObTableOperationRequest), table::ObTableOperationResult);
RPC_S(PR5 batch_execute, obrpc::OB_TABLE_API_BATCH_EXECUTE, (table::ObTableBatchOperationRequest), table::ObTableBatchOperationResult);
RPC_SS(PR5 execute_query, obrpc::OB_TABLE_API_EXECUTE_QUERY, (table::ObTableQueryRequest), table::ObTableQueryResult);
RPC_S(PR5 query_and_mutate, obrpc::OB_TABLE_API_QUERY_AND_MUTATE, (table::ObTableQueryAndMutateRequest), table::ObTableQueryAndMutateResult);
};
}; // end namespace obrpc

View File

@ -76,3 +76,12 @@ OB_SERIALIZE_MEMBER(ObTableQueryRequest,
consistency_level_,
query_
);
////////////////////////////////////////////////////////////////
OB_SERIALIZE_MEMBER(ObTableQueryAndMutateRequest,
credential_,
table_name_,
table_id_,
partition_id_,
entity_type_,
query_and_mutate_);

View File

@ -215,6 +215,31 @@ public:
virtual bool has_more_result() const = 0;
};
class ObTableQueryAndMutateRequest final
{
OB_UNIS_VERSION(1);
public:
ObTableQueryAndMutateRequest()
:table_id_(common::OB_INVALID_ID),
partition_id_(common::OB_INVALID_ID),
binlog_row_image_type_(ObBinlogRowImageType::FULL)
{}
TO_STRING_KV("credential", common::ObHexStringWrap(credential_),
K_(table_name),
K_(table_id),
K_(partition_id),
K_(entity_type),
K_(query_and_mutate));
public:
ObString credential_;
ObString table_name_;
uint64_t table_id_; // for optimize purpose
/// partition id. Set it to gain better performance. If unknown, set it to be OB_INVALID_ID
uint64_t partition_id_; // for optimize purpose
ObTableEntityType entity_type_; // for optimize purpose
ObTableQueryAndMutate query_and_mutate_;
ObBinlogRowImageType binlog_row_image_type_;
};
} // end namespace table
} // end namespace oceanbase

View File

@ -5,3 +5,4 @@ ob_unittest(test_worker_pool omt/test_worker_pool.cpp)
ob_unittest(test_token_calcer omt/test_token_calcer.cpp)
ob_unittest(test_information_schema)
ob_unittest(test_tableapi tableapi/test_tableapi.cpp)
ob_unittest(test_hbaseapi hbaseapi/test_hfilter_parser.cpp)

View File

@ -0,0 +1,148 @@
/**
* (C) 2010-2018 Alibaba Group Holding Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* Version: $Id$
*
* test_hfilter_parser.cpp
*
* Authors:
* Zhifeng YANG <zhuweng.yzf@alipay.com>
*
*/
#include "observer/table/ob_htable_filter_parser.h"
#include "observer/table/ob_htable_filters.h"
#include <gtest/gtest.h>
#include "lib/utility/ob_test_util.h"
#include "lib/json/ob_json_print_utils.h" // for SJ
#include <fstream>
using namespace oceanbase::common;
using namespace oceanbase::table;
class TestHFilterParser: public ::testing::Test
{
public:
TestHFilterParser();
virtual ~TestHFilterParser();
virtual void SetUp();
virtual void TearDown();
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(TestHFilterParser);
protected:
// function members
void do_parse(const char *filter_cstr, std::ofstream &of_result, int64_t expect_error);
bool is_prefix_equal(const char* tmp_file, const char* result_file);
void is_equal_content(const char* tmp_file, const char* result_file);
};
TestHFilterParser::TestHFilterParser()
{
}
TestHFilterParser::~TestHFilterParser()
{
}
void TestHFilterParser::SetUp()
{
}
void TestHFilterParser::TearDown()
{
}
bool TestHFilterParser::is_prefix_equal(const char* tmp_file, const char* result_file)
{
std::ifstream if_test(tmp_file);
if_test.is_open();
EXPECT_EQ(true, if_test.is_open());
std::istream_iterator<std::string> it_test(if_test);
std::ifstream if_expected(result_file);
if_expected.is_open();
EXPECT_EQ(true, if_expected.is_open());
std::istream_iterator<std::string> it_expected(if_expected);
return std::equal(it_test, std::istream_iterator<std::string>(), it_expected);
}
void TestHFilterParser::is_equal_content(const char* tmp_file, const char* result_file)
{
bool is_equal = is_prefix_equal(tmp_file, result_file) & is_prefix_equal(result_file, tmp_file);
_OB_LOG(WARN, "result file is %s, expect file is %s, is_equal:%d", tmp_file, result_file, is_equal);
if (is_equal) {
std::remove(tmp_file);
} else {
fprintf(stdout, "The result files mismatched, you can choose to\n");
fprintf(stdout, "diff -u %s %s\n", tmp_file, result_file);
}
EXPECT_EQ(true, is_equal);
}
void TestHFilterParser::do_parse(const char *filter_cstr, std::ofstream &of_result, int64_t expect_error)
{
ObArenaAllocator allocator;
ObHTableFilterParser parser;
ASSERT_EQ(OB_SUCCESS, parser.init(&allocator));
ObString filter_string = ObString::make_string(filter_cstr);
int ret = OB_SUCCESS;
_OB_LOG(INFO, "FILTER: >>>%.*s<<<", filter_string.length(), filter_string.ptr());
hfilter::Filter *filter = NULL;
ret = parser.parse_filter(filter_string, filter);
if (OB_FAIL(ret)) {
_OB_LOG(WARN, "failed to parse filter. msg=%s [%d.%d-%d.%d]", parser.error_msg_,
parser.first_line_, parser.first_column_, parser.last_line_, parser.last_column_);
}
ASSERT_EQ(expect_error, -ret);
if (NULL != filter){
of_result << SJ(*filter) << std::endl;
}
parser.destroy();
}
TEST_F(TestHFilterParser, basic_test)
{
const char* test_file = "./hfilter_parser.test";
const char* result_file = "./hfilter_parser.result";
const char* tmp_file = "./hfilter_parser.tmp";
// run tests
std::ifstream if_tests(test_file);
ASSERT_TRUE(if_tests.is_open());
std::ofstream of_result(tmp_file);
ASSERT_TRUE(of_result.is_open());
std::string line;
int64_t case_id = 0;
int64_t expect_error = 0;
char *w = NULL;
char *p = NULL;
UNUSED(w);
while (std::getline(if_tests, line)) {
if (line.size() <= 0) continue;
if (line.at(0) == '#') continue;
if (strncmp(line.c_str(), "--error", strlen("--error")) == 0) {
p = const_cast<char*>(line.c_str());
w = strsep(&p, " ");
expect_error = atol(p);
continue;
}
of_result << "************** Case "<< ++case_id << " ***************" << std::endl;
of_result << line << std::endl;
ASSERT_NO_FATAL_FAILURE(do_parse(line.c_str(), of_result, expect_error));
if (expect_error != 0) {
expect_error = 0;
}
}
of_result.close();
// verify results
is_equal_content(tmp_file, result_file);
}
int main(int argc, char **argv)
{
OB_LOGGER.set_log_level("INFO");
OB_LOGGER.set_file_name("test_hfilter_parser.log", true);
::testing::InitGoogleTest(&argc,argv);
return RUN_ALL_TESTS();
}