You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-10-30 07:25:34 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			373 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			373 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (C) 2014 InfiniDB, Inc.
 | |
|    Copyright (C) 2016 MariaDB Corporation
 | |
|    Copyright (C) 2019 MariaDB Corporation
 | |
| 
 | |
|    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; version 2 of
 | |
|    the License.
 | |
| 
 | |
|    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, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 | |
|    MA 02110-1301, USA. */
 | |
| #pragma once
 | |
| 
 | |
| #include <my_config.h>
 | |
| #include "idb_mysql.h"
 | |
| #include "ha_mcs_sysvars.h"
 | |
| #pragma GCC diagnostic push
 | |
| #pragma GCC diagnostic ignored "-Wunused-parameter"
 | |
| #include "ha_maria.h"
 | |
| #pragma GCC diagnostic pop
 | |
| 
 | |
| extern handlerton* mcs_hton;
 | |
| 
 | |
| /** @brief
 | |
|   COLUMNSTORE_SHARE is a structure that will be shared among all open handlers.
 | |
|   This example implements the minimum of what you will probably need.
 | |
| */
 | |
| typedef struct st_mcs_share
 | |
| {
 | |
|   char* table_name;
 | |
|   uint32_t table_name_length, use_count;
 | |
|   pthread_mutex_t mutex;
 | |
|   THR_LOCK lock;
 | |
| } COLUMNSTORE_SHARE;
 | |
| 
 | |
| /** @brief
 | |
|   Class definition for the storage engine
 | |
| */
 | |
| class ha_mcs : public handler
 | |
| {
 | |
|   THR_LOCK_DATA lock;        ///< MySQL lock
 | |
|   COLUMNSTORE_SHARE* share;  ///< Shared lock info
 | |
|   ulonglong int_table_flags;
 | |
|   // We are using a vector here to mimic the stack functionality
 | |
|   // using push_back() and pop_back()
 | |
|   // as apparently there is a linker error on the std::stack<COND*>::pop()
 | |
|   // call on Ubuntu18.
 | |
|   std::vector<COND*> condStack;
 | |
|   int m_lock_type;
 | |
|   long time_zone;
 | |
| 
 | |
|   int impl_external_lock(THD* thd, TABLE* table, int lock_type);
 | |
|   int impl_rnd_init(TABLE* table, const std::vector<COND*>& condStack);
 | |
| 
 | |
| protected:
 | |
|   ha_rows& rows_inserted()
 | |
|   {
 | |
| #if MYSQL_VERSION_ID >= 110500
 | |
|     return rows_stats.inserted;
 | |
| #else
 | |
|     return rows_changed;
 | |
| #endif
 | |
|   }
 | |
| 
 | |
|  public:
 | |
|   ha_mcs(handlerton* hton, TABLE_SHARE* table_arg);
 | |
|   ~ha_mcs() override = default;
 | |
| 
 | |
|   /** @brief
 | |
|     The name that will be used for display purposes.
 | |
|    */
 | |
|   const char* table_type() const override
 | |
|   {
 | |
|     return "ColumnStore";
 | |
|   }
 | |
| 
 | |
|   /** @brief
 | |
|     The name of the index type that will be used for display.
 | |
|     Don't implement this method unless you really have indexes.
 | |
|    */
 | |
|   // const char *index_type(uint32_t inx) { return "HASH"; }
 | |
| 
 | |
|   /** @brief
 | |
|     The file extensions.
 | |
|    */
 | |
|   const char** bas_ext() const;
 | |
| 
 | |
|   /** @brief
 | |
|     This is a list of flags that indicate what functionality the storage engine
 | |
|     implements. The current table flags are documented in handler.h
 | |
|   */
 | |
|   ulonglong table_flags() const override
 | |
|   {
 | |
|     return int_table_flags;
 | |
|   }
 | |
| 
 | |
|   /** @brief
 | |
|     This is a bitmap of flags that indicates how the storage engine
 | |
|     implements indexes. The current index flags are documented in
 | |
|     handler.h. If you do not implement indexes, just return zero here.
 | |
| 
 | |
|       @details
 | |
|     part is the key part to check. First key part is 0.
 | |
|     If all_parts is set, MySQL wants to know the flags for the combined
 | |
|     index, up to and including 'part'.
 | |
|   */
 | |
|   ulong index_flags(uint32_t /*inx*/, uint32_t /*part*/, bool /*all_parts*/) const override
 | |
|   {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   /** @brief
 | |
|     unireg.cc will call max_supported_record_length(), max_supported_keys(),
 | |
|     max_supported_key_parts(), uint32_t max_supported_key_length()
 | |
|     to make sure that the storage engine can handle the data it is about to
 | |
|     send. Return *real* limits of your storage engine here; MySQL will do
 | |
|     min(your_limits, MySQL_limits) automatically.
 | |
|    */
 | |
|   uint32_t max_supported_record_length() const override
 | |
|   {
 | |
|     return HA_MAX_REC_LENGTH;
 | |
|   }
 | |
| 
 | |
| #ifdef MARIADB_NEW_COST_MODEL
 | |
|   /** @brief
 | |
|     Called in test_quick_select to determine if indexes should be used.
 | |
|   */
 | |
|   virtual IO_AND_CPU_COST scan_time() override
 | |
|   {
 | |
|     IO_AND_CPU_COST cost;
 | |
|     cost.io = 0.0;
 | |
|     /*
 | |
|       For now, assume all cost is CPU cost.
 | |
|       The numbers are also very inadequate for the new cost model.
 | |
|     */
 | |
|     cost.cpu = (double)(stats.records + stats.deleted) / 20.0 + 10;
 | |
|     return cost;
 | |
|   }
 | |
| #else
 | |
|   /** @brief
 | |
|     Called in test_quick_select to determine if indexes should be used.
 | |
|   */
 | |
|   double scan_time() override
 | |
|   {
 | |
|     return (double)(stats.records + stats.deleted) / 20.0 + 10;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   /** @brief
 | |
|     Analyze table command.
 | |
|   */
 | |
|   int analyze(THD* thd, HA_CHECK_OPT* check_opt) override;
 | |
| 
 | |
|   /*
 | |
|     Everything below are methods that we implement in ha_example.cc.
 | |
| 
 | |
|     Most of these methods are not obligatory, skip them and
 | |
|     MySQL will treat them as not implemented
 | |
|   */
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc; it's a required method.
 | |
|   */
 | |
|   int open(const char* name, int mode, uint32_t test_if_locked) override;  // required
 | |
| 
 | |
|   // MCOL-4282 This function is called by open_tables in sql_base.cc.
 | |
|   // We mutate the optimizer flags here for prepared statements as this
 | |
|   // handler function is called before JOIN::prepare, and we need to
 | |
|   // disable the default optimizer flags before JOIN::prepare (which is
 | |
|   // called during "PREPARE stmt FROM ..." SQL) is called.
 | |
|   // Sequence of SQL statements that will lead to this execution path
 | |
|   // for prepared statements:
 | |
|   //   CREATE TABLE t1 (a int, b int) engine=columnstore;
 | |
|   //   INSERT INTO t1 VALUES (1, 2), (2, 4), (3, 1);
 | |
|   //   PREPARE stmt1 FROM "SELECT * FROM t1";
 | |
|   //   EXECUTE stmt1;
 | |
| 
 | |
|   int discover_check_version() override;
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc; it's a required method.
 | |
|   */
 | |
|   int close() override;  // required
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc. It's not an obligatory method;
 | |
|     skip it and and MySQL will treat it as not implemented.
 | |
|   */
 | |
|   int write_row(const uchar* buf) override;
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc. It's not an obligatory method;
 | |
|     skip it and and MySQL will treat it as not implemented.
 | |
|   */
 | |
|   void start_bulk_insert(ha_rows rows, uint flags = 0) override;
 | |
|   void start_bulk_insert_from_cache(ha_rows rows, uint flags = 0);
 | |
| 
 | |
|   /**@bug 2461 - Overloaded end_bulk_insert.  MariaDB uses the abort bool, mysql does not. */
 | |
|   int end_bulk_insert() override;
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc. It's not an obligatory method;
 | |
|     skip it and and MySQL will treat it as not implemented.
 | |
|   */
 | |
|   int update_row(const uchar* old_data, const uchar* new_data) override;
 | |
|   int direct_update_rows_init(List<Item>* update_fields) override;
 | |
|   int direct_update_rows(ha_rows* update_rows);
 | |
|   int direct_update_rows(ha_rows* update_rows, ha_rows* found_rows) override;
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc. It's not an obligatory method;
 | |
|     skip it and and MySQL will treat it as not implemented.
 | |
|   */
 | |
|   int delete_row(const uchar* buf) override;
 | |
|   int direct_delete_rows_init() override;
 | |
|   int direct_delete_rows(ha_rows* deleted_rows) override;
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc. It's not an obligatory method;
 | |
|     skip it and and MySQL will treat it as not implemented.
 | |
|   */
 | |
|   int index_read_map(uchar* buf, const uchar* key, key_part_map keypart_map,
 | |
|                      enum ha_rkey_function find_flag) override;
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc. It's not an obligatory method;
 | |
|     skip it and and MySQL will treat it as not implemented.
 | |
|   */
 | |
|   int index_next(uchar* buf) override;
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc. It's not an obligatory method;
 | |
|     skip it and and MySQL will treat it as not implemented.
 | |
|   */
 | |
|   int index_prev(uchar* buf) override;
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc. It's not an obligatory method;
 | |
|     skip it and and MySQL will treat it as not implemented.
 | |
|   */
 | |
|   int index_first(uchar* buf) override;
 | |
| 
 | |
|   /** @brief
 | |
|     We implement this in ha_example.cc. It's not an obligatory method;
 | |
|     skip it and and MySQL will treat it as not implemented.
 | |
|   */
 | |
|   int index_last(uchar* buf) override;
 | |
| 
 | |
|   /** @brief
 | |
|     Unlike index_init(), rnd_init() can be called two consecutive times
 | |
|     without rnd_end() in between (it only makes sense if scan=1). In this
 | |
|     case, the second call should prepare for the new table scan (e.g if
 | |
|     rnd_init() allocates the cursor, the second call should position the
 | |
|     cursor to the start of the table; no need to deallocate and allocate
 | |
|     it again. This is a required method.
 | |
|   */
 | |
|   int rnd_init(bool scan) override;  // required
 | |
|   int rnd_end() override;
 | |
|   int rnd_next(uchar* buf) override;             ///< required
 | |
|   int rnd_pos(uchar* buf, uchar* pos) override;  ///< required
 | |
|   int reset() override;
 | |
|   void position(const uchar* record) override;  ///< required
 | |
|   int info(uint32_t) override;                  ///< required
 | |
|   int extra(enum ha_extra_function operation) override;
 | |
|   int external_lock(THD* thd, int lock_type) override;  ///< required
 | |
|   int delete_all_rows() override;
 | |
|   ha_rows records_in_range(uint32_t inx, const key_range* min_key, const key_range* max_key,
 | |
|                            page_range* res) override;
 | |
|   int delete_table(const char* from) override;
 | |
|   int rename_table(const char* from, const char* to) override;
 | |
|   int create(const char* name, TABLE* form,
 | |
|              HA_CREATE_INFO* create_info) override;  ///< required
 | |
| 
 | |
|   THR_LOCK_DATA** store_lock(THD* thd, THR_LOCK_DATA** to,
 | |
|                              enum thr_lock_type lock_type) override;  ///< required
 | |
|   const COND* cond_push(const COND* cond) override;
 | |
|   void cond_pop() override;
 | |
|   uint8 table_cache_type() override
 | |
|   {
 | |
|     return HA_CACHE_TBL_NOCACHE;
 | |
|   }
 | |
| 
 | |
|   int repair(THD* thd, HA_CHECK_OPT* check_opt) override;
 | |
|   bool is_crashed() const override;
 | |
| 
 | |
|   bool isReadOnly() const
 | |
|   {
 | |
|     return m_lock_type == F_RDLCK;
 | |
|   }
 | |
| };
 | |
| 
 | |
| class ha_mcs_cache_share
 | |
| {
 | |
|   ha_mcs_cache_share* next; /* Next open share */
 | |
|   const char* name;
 | |
|   uint open_count;
 | |
| 
 | |
|  public:
 | |
|   ulonglong cached_rows;
 | |
|   THR_LOCK org_lock;
 | |
|   friend ha_mcs_cache_share* find_cache_share(const char* name, ulonglong cached_rows);
 | |
|   void close();
 | |
| };
 | |
| 
 | |
| class ha_mcs_cache : public ha_mcs
 | |
| {
 | |
|   typedef ha_mcs parent;
 | |
|   int original_lock_type;
 | |
|   bool insert_command, cache_locked;
 | |
|   enum_sql_command sql_command;
 | |
| 
 | |
|   // True if this handler belongs to either calpontsys.systable or
 | |
|   // calpontsys.syscolumn system catalog tables
 | |
|   bool isSysCatTable;
 | |
| 
 | |
|   // True if the ColumnStore table is not cached (i.e. when the table
 | |
|   // was created with columnstore_cache_inserts=OFF).
 | |
|   bool isCacheDisabled;
 | |
| 
 | |
|   bool isCacheEnabled() const
 | |
|   {
 | |
|     return (get_cache_inserts(current_thd) && !isSysCatTable && !isCacheDisabled);
 | |
|   }
 | |
| 
 | |
|  public:
 | |
|   uint lock_counter;
 | |
|   ha_maria* cache_handler;
 | |
|   ha_mcs_cache_share* share;
 | |
| 
 | |
|   ha_mcs_cache(handlerton* hton, TABLE_SHARE* table_arg, MEM_ROOT* mem_root);
 | |
|   ~ha_mcs_cache() override;
 | |
| 
 | |
|   /*
 | |
|     The following functions duplicates calls to derived handler and
 | |
|     cache handler
 | |
|   */
 | |
| 
 | |
|   int create(const char* name, TABLE* table_arg, HA_CREATE_INFO* ha_create_info) override;
 | |
|   int open(const char* name, int mode, uint open_flags) override;
 | |
|   int delete_table(const char* name) override;
 | |
|   int rename_table(const char* from, const char* to) override;
 | |
|   int delete_all_rows() override;
 | |
|   int close() override;
 | |
| 
 | |
|   uint lock_count() const override;
 | |
|   THR_LOCK_DATA** store_lock(THD* thd, THR_LOCK_DATA** to, enum thr_lock_type lock_type) override;
 | |
|   int external_lock(THD* thd, int lock_type) override;
 | |
|   int repair(THD* thd, HA_CHECK_OPT* check_opt) override;
 | |
|   bool is_crashed() const override;
 | |
| 
 | |
|   /*
 | |
|     Write row uses cache_handler, for normal inserts, otherwise derived
 | |
|     handler
 | |
|   */
 | |
|   int write_row(const uchar* buf) override;
 | |
|   void start_bulk_insert(ha_rows rows, uint flags) override;
 | |
|   int end_bulk_insert() override;
 | |
| 
 | |
|   /* Cache functions */
 | |
|   void free_locks();
 | |
|   ha_rows num_rows_cached();
 | |
|   int flush_insert_cache();
 | |
|   friend my_bool get_status_and_flush_cache(void* param, my_bool concurrent_insert);
 | |
|   friend my_bool cache_start_trans(void* param);
 | |
| };
 |