[tableapi] support hbase api
This commit is contained in:
parent
d1707e6a19
commit
97b4a6afb8
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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_);
|
||||
|
11
src/observer/table/gen_htable_parser.sh
Executable file
11
src/observer/table/gen_htable_parser.sh
Executable 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
|
2275
src/observer/table/htable_filter_lex.cxx
Normal file
2275
src/observer/table/htable_filter_lex.cxx
Normal file
File diff suppressed because it is too large
Load Diff
354
src/observer/table/htable_filter_lex.hxx
Normal file
354
src/observer/table/htable_filter_lex.hxx
Normal 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 */
|
109
src/observer/table/htable_filter_lex.lxx
Normal file
109
src/observer/table/htable_filter_lex.lxx
Normal 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
|
2124
src/observer/table/htable_filter_tab.cxx
Normal file
2124
src/observer/table/htable_filter_tab.cxx
Normal file
File diff suppressed because it is too large
Load Diff
110
src/observer/table/htable_filter_tab.hxx
Normal file
110
src/observer/table/htable_filter_tab.hxx
Normal 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
|
||||
|
||||
|
||||
|
349
src/observer/table/htable_filter_tab.yxx
Normal file
349
src/observer/table/htable_filter_tab.yxx
Normal 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; }
|
||||
;
|
||||
%%
|
1161
src/observer/table/ob_htable_filter_operator.cpp
Normal file
1161
src/observer/table/ob_htable_filter_operator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
253
src/observer/table/ob_htable_filter_operator.h
Normal file
253
src/observer/table/ob_htable_filter_operator.h
Normal 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 */
|
229
src/observer/table/ob_htable_filter_parser.cpp
Normal file
229
src/observer/table/ob_htable_filter_parser.cpp
Normal 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);
|
||||
}
|
95
src/observer/table/ob_htable_filter_parser.h
Normal file
95
src/observer/table/ob_htable_filter_parser.h
Normal 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 */
|
913
src/observer/table/ob_htable_filters.cpp
Normal file
913
src/observer/table/ob_htable_filters.cpp
Normal 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;
|
||||
}
|
492
src/observer/table/ob_htable_filters.h
Normal file
492
src/observer/table/ob_htable_filters.h
Normal 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 */
|
312
src/observer/table/ob_htable_utils.cpp
Normal file
312
src/observer/table/ob_htable_utils.cpp
Normal 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;
|
||||
}
|
313
src/observer/table/ob_htable_utils.h
Normal file
313
src/observer/table/ob_htable_utils.h
Normal 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 */
|
@ -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;
|
||||
}
|
@ -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_;
|
||||
|
@ -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) {
|
||||
|
292
src/observer/table/ob_table_query_and_mutate_processor.cpp
Normal file
292
src/observer/table/ob_table_query_and_mutate_processor.cpp
Normal 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;
|
||||
}
|
56
src/observer/table/ob_table_query_and_mutate_processor.h
Normal file
56
src/observer/table/ob_table_query_and_mutate_processor.h
Normal 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 */
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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_);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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_);
|
@ -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
|
||||
|
@ -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)
|
||||
|
148
unittest/observer/hbaseapi/test_hfilter_parser.cpp
Normal file
148
unittest/observer/hbaseapi/test_hfilter_parser.cpp
Normal 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();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user