Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-14959

Control over memory allocated for SP/PS

Details

    Description

      SP/PS (Stored Procedures / Prepared Statements) allocates memory till the PS cache of SP will be destroyed. There is no way to see how many memory allocated and if it grows with each execution (first 2 execution can lead to new memory allocation but not more)

      Task minimum:
      Status variables which count the memory used/allocated for SP/PS by thread and/or for the server.

      Other ideas:

      • Automatic stop allocation in debugging version after second execution and call exception on attempt.
      • Information schema by threads and SP/PS with information about allocated and used memory

      Information can be collected in MEM_ROOTs of SP/PS. Storing info about status of mem_root before execution then checking after new allocated memory can be found.

      MEM_ROOT can be changed to have debug mode which make it read only which can be switched on after second execution.

      Attachments

        Issue Links

          Activity

            xzx Zhangxian Xu added a comment -

            Hi, I'm Zhangxian Xu, a student pursuing master's degree in Computer Science. It's a nice issue and I want to complete it as my Gsoc 2021 project . Hope to get some guidence on this issue. Thanks!

            xzx Zhangxian Xu added a comment - Hi, I'm Zhangxian Xu, a student pursuing master's degree in Computer Science. It's a nice issue and I want to complete it as my Gsoc 2021 project . Hope to get some guidence on this issue. Thanks!

            a draft

            diff --git a/include/my_alloc.h b/include/my_alloc.h
            index 52c04fe1b7d..4e67f4a1ee3 100644
            --- a/include/my_alloc.h
            +++ b/include/my_alloc.h
            @@ -49,6 +49,9 @@ typedef struct st_mem_root
                  MAX_BLOCK_USAGE_BEFORE_DROP block will be dropped in 'used' list)
               */
               unsigned int first_block_usage;
            +#ifndef DBUG_OFF
            +  my_bool read_only;
            +#endif
             
               void (*error_handler)(void);
             } MEM_ROOT;
            diff --git a/include/mysql.h.pp b/include/mysql.h.pp
            index 73b9f9f588b..4eea704165f 100644
            --- a/include/mysql.h.pp
            +++ b/include/mysql.h.pp
            @@ -238,6 +238,7 @@ typedef struct st_mem_root
               size_t block_size;
               unsigned int block_num;
               unsigned int first_block_usage;
            +  my_bool read_only;
               void (*error_handler)(void);
             } MEM_ROOT;
             typedef struct st_typelib {
            diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
            index d67b8be9bb8..8c09e4bab68 100644
            --- a/mysys/my_alloc.c
            +++ b/mysys/my_alloc.c
            @@ -71,6 +71,9 @@ void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
               mem_root->error_handler= 0;
               mem_root->block_num= 4;			/* We shift this with >>2 */
               mem_root->first_block_usage= 0;
            +#ifndef DBUG_OFF
            +  mem_root->read_only= 0;
            +#endif
             
             #if !(defined(HAVE_valgrind) && defined(EXTRA_DEBUG))
               if (pre_alloc_size)
            @@ -177,6 +180,8 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length)
             
               DBUG_ASSERT(alloc_root_inited(mem_root));
             
            +  DBUG_ASSERT(mem_root->read_only == 0);
            +
               DBUG_EXECUTE_IF("simulate_out_of_memory",
                               {
                                 if (mem_root->error_handler)
            @@ -210,6 +215,8 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length)
               DBUG_PRINT("enter",("root: %p", mem_root));
               DBUG_ASSERT(alloc_root_inited(mem_root));
             
            +  DBUG_ASSERT(mem_root->read_only == 0);
            +
               DBUG_EXECUTE_IF("simulate_out_of_memory",
                               {
                                 /* Avoid reusing an already allocated block */
            diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
            index 64e4cd30561..726e1634904 100644
            --- a/sql/sql_prepare.cc
            +++ b/sql/sql_prepare.cc
            @@ -167,6 +167,9 @@ class Prepared_statement: public Statement
               Server_side_cursor *cursor;
               uchar *packet;
               uchar *packet_end;
            +#ifndef DBUG_OFF
            +  ulong executed_counter;
            +#endif
               uint param_count;
               uint last_errno;
               uint flags;
            @@ -3996,6 +3999,9 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
               cursor(0),
               packet(0),
               packet_end(0),
            +#ifndef DBUG_OFF
            +  executed_counter(0),
            +#endif
               param_count(0),
               last_errno(0),
               flags((uint) IS_IN_USE),
            @@ -4069,8 +4075,8 @@ void Prepared_statement::setup_set_params()
             Prepared_statement::~Prepared_statement()
             {
               DBUG_ENTER("Prepared_statement::~Prepared_statement");
            -  DBUG_PRINT("enter",("stmt: %p  cursor: %p",
            -                      this, cursor));
            +  DBUG_PRINT("enter",("stmt: %p  cursor: %p, executed: %lu",
            +                      this, cursor, executed_counter));
               delete cursor;
               /*
                 We have to call free on the items even if cleanup is called as some items,
            @@ -4228,6 +4234,9 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
                 init_param_array(this);
             
               lex->set_trg_event_type_for_tables();
            +#ifndef DBUG_OFF
            +  executed_counter= 0;
            +#endif
             
               /*
                 While doing context analysis of the query (in check_prepared_statement)
            @@ -4525,6 +4534,16 @@ Prepared_statement::execute_loop(String *expanded_query,
                   goto reexecute;
               }
               reset_stmt_params(this);
            +#ifndef DBUG_OFF
            +  if (!error)
            +  {
            +    if (++executed_counter >= 2)
            +    {
            +      mem_root->read_only= 1;
            +    }
            +    DBUG_PRINT("XXX", ("execute counter: %lu", executed_counter));
            +  }
            +#endif
             
               return error;
             }
            

            sanja Oleksandr Byelkin added a comment - a draft diff --git a/include/my_alloc.h b/include/my_alloc.h index 52c04fe1b7d..4e67f4a1ee3 100644 --- a/include/my_alloc.h +++ b/include/my_alloc.h @@ -49,6 +49,9 @@ typedef struct st_mem_root MAX_BLOCK_USAGE_BEFORE_DROP block will be dropped in 'used' list) */ unsigned int first_block_usage; +#ifndef DBUG_OFF + my_bool read_only; +#endif void (*error_handler)(void); } MEM_ROOT; diff --git a/include/mysql.h.pp b/include/mysql.h.pp index 73b9f9f588b..4eea704165f 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -238,6 +238,7 @@ typedef struct st_mem_root size_t block_size; unsigned int block_num; unsigned int first_block_usage; + my_bool read_only; void (*error_handler)(void); } MEM_ROOT; typedef struct st_typelib { diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index d67b8be9bb8..8c09e4bab68 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -71,6 +71,9 @@ void init_alloc_root(MEM_ROOT *mem_root, size_t block_size, mem_root->error_handler= 0; mem_root->block_num= 4; /* We shift this with >>2 */ mem_root->first_block_usage= 0; +#ifndef DBUG_OFF + mem_root->read_only= 0; +#endif #if !(defined(HAVE_valgrind) && defined(EXTRA_DEBUG)) if (pre_alloc_size) @@ -177,6 +180,8 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length) DBUG_ASSERT(alloc_root_inited(mem_root)); + DBUG_ASSERT(mem_root->read_only == 0); + DBUG_EXECUTE_IF("simulate_out_of_memory", { if (mem_root->error_handler) @@ -210,6 +215,8 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length) DBUG_PRINT("enter",("root: %p", mem_root)); DBUG_ASSERT(alloc_root_inited(mem_root)); + DBUG_ASSERT(mem_root->read_only == 0); + DBUG_EXECUTE_IF("simulate_out_of_memory", { /* Avoid reusing an already allocated block */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 64e4cd30561..726e1634904 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -167,6 +167,9 @@ class Prepared_statement: public Statement Server_side_cursor *cursor; uchar *packet; uchar *packet_end; +#ifndef DBUG_OFF + ulong executed_counter; +#endif uint param_count; uint last_errno; uint flags; @@ -3996,6 +3999,9 @@ Prepared_statement::Prepared_statement(THD *thd_arg) cursor(0), packet(0), packet_end(0), +#ifndef DBUG_OFF + executed_counter(0), +#endif param_count(0), last_errno(0), flags((uint) IS_IN_USE), @@ -4069,8 +4075,8 @@ void Prepared_statement::setup_set_params() Prepared_statement::~Prepared_statement() { DBUG_ENTER("Prepared_statement::~Prepared_statement"); - DBUG_PRINT("enter",("stmt: %p cursor: %p", - this, cursor)); + DBUG_PRINT("enter",("stmt: %p cursor: %p, executed: %lu", + this, cursor, executed_counter)); delete cursor; /* We have to call free on the items even if cleanup is called as some items, @@ -4228,6 +4234,9 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) init_param_array(this); lex->set_trg_event_type_for_tables(); +#ifndef DBUG_OFF + executed_counter= 0; +#endif /* While doing context analysis of the query (in check_prepared_statement) @@ -4525,6 +4534,16 @@ Prepared_statement::execute_loop(String *expanded_query, goto reexecute; } reset_stmt_params(this); +#ifndef DBUG_OFF + if (!error) + { + if (++executed_counter >= 2) + { + mem_root->read_only= 1; + } + DBUG_PRINT("XXX", ("execute counter: %lu", executed_counter)); + } +#endif return error; }

            People

              shulga Dmitry Shulga
              sanja Oleksandr Byelkin
              Votes:
              3 Vote for this issue
              Watchers:
              12 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.