P_S.file_summary_by_instance uses key_value_cache
[pstop.git] / performance_schema / file_summary_by_instance / file_summary_by_instance_row.go
index 64dd145..3cf01a1 100644 (file)
@@ -8,7 +8,10 @@ import (
        "log"
        "regexp"
        "sort"
+       //      "strconv"
+       "time"
 
+       "github.com/sjmudd/pstop/key_value_cache"
        "github.com/sjmudd/pstop/lib"
 )
 
@@ -43,6 +46,32 @@ CREATE TABLE `file_summary_by_instance` (
 1 row in set (0.00 sec)
 */
 
+//     foo/../bar --> foo/bar   perl: $new =~ s{[^/]+/\.\./}{/};
+//     /./        --> /         perl: $new =~ s{/\./}{};
+//     //         --> /         perl: $new =~ s{//}{/};
+const (
+       re_encoded = `@(\d{4})` // FIXME - add me to catch @0024 --> $ for example
+)
+
+var (
+       re_one_or_the_other    *regexp.Regexp = regexp.MustCompile(`/(\.)?/`)
+       re_slash_dot_dot_slash *regexp.Regexp = regexp.MustCompile(`[^/]+/\.\./`)
+       re_table_file          *regexp.Regexp = regexp.MustCompile(`/([^/]+)/([^/]+)\.(frm|ibd|MYD|MYI|CSM|CSV|par)$`)
+       re_temp_table          *regexp.Regexp = regexp.MustCompile(`#sql-[0-9_]+`)
+       re_part_table          *regexp.Regexp = regexp.MustCompile(`(.+)#P#p(\d+|MAX)`)
+       re_ibdata              *regexp.Regexp = regexp.MustCompile(`/ibdata\d+$`)
+       re_redo_log            *regexp.Regexp = regexp.MustCompile(`/ib_logfile\d+$`)
+       re_binlog              *regexp.Regexp = regexp.MustCompile(`/binlog\.(\d{6}|index)$`)
+       re_db_opt              *regexp.Regexp = regexp.MustCompile(`/db\.opt$`)
+       re_slowlog             *regexp.Regexp = regexp.MustCompile(`/slowlog$`)
+       re_auto_cnf            *regexp.Regexp = regexp.MustCompile(`/auto\.cnf$`)
+       re_pid_file            *regexp.Regexp = regexp.MustCompile(`/[^/]+\.pid$`)
+       re_error_msg           *regexp.Regexp = regexp.MustCompile(`/share/[^/]+/errmsg\.sys$`)
+       re_charset             *regexp.Regexp = regexp.MustCompile(`/share/charsets/Index\.xml$`)
+
+       cache key_value_cache.KeyValueCache
+)
+
 type file_summary_by_instance_row struct {
        FILE_NAME string
 
@@ -164,23 +193,11 @@ func (t file_summary_by_instance_rows) totals() file_summary_by_instance_row {
 
 // clean up the given path reducing redundant stuff and return the clean path
 func cleanup_path(path string) string {
-       //     foo/../bar --> bar       perl: $new =~ s{[^/]+/\.\./}{/};
-       //     foo/./bar  --> foo/bar   perl: $new =~ s{/\./}{};
-       //     //         --> /         perl: $new =~ s{//}{/};
-       const (
-               double_slash_re        = `//`
-               slash_dot_slash_re     = `/\./`
-               slash_dot_dot_slash_re = `[^/]+/\.\./`
-       )
+
        for {
                orig_path := path
-
-               r := regexp.MustCompile(double_slash_re)
-               path = r.ReplaceAllString(path, "")
-               r = regexp.MustCompile(slash_dot_slash_re)
-               path = r.ReplaceAllString(path, "")
-               r = regexp.MustCompile(slash_dot_dot_slash_re)
-               path = r.ReplaceAllString(path, "")
+               path = re_one_or_the_other.ReplaceAllString(path, "/")
+               path = re_slash_dot_dot_slash.ReplaceAllString(path, "/")
                if orig_path == path { // no change so give up
                        break
                }
@@ -192,60 +209,53 @@ func cleanup_path(path string) string {
 // From the original FILE_NAME we want to generate a simpler name to use.
 // This simpler name may also merge several different filenames into one.
 func (t file_summary_by_instance_row) simple_name(global_variables map[string]string) string {
-       const (
-               auto_cnf_re  = `/auto\.cnf$`
-               binlog_re    = `/binlog\.(\d{6}|index)$`
-               charset_re   = `/share/charsets/Index\.xml$`
-               db_opt_re    = `/db\.opt$`
-               error_msg_re = `/share/[^/]+/errmsg\.sys$`
-               ibdata_re    = `/ibdata\d+$`
-               redo_log_re  = `/ib_logfile\d+$`
-               pid_file_re  = `/[^/]+\.pid$`
-               //              relay_log_re  = `/mysql-relay-bin.(\d{6}|index)$`
-               relative_path_re = `^\.\./`
-               current_dir_re   = `^\./`
-               slowlog_re       = `/slowlog$`
-               table_file_re    = `/([^/]+)/([^/]+)\.(frm|ibd|MYD|MYI|CSM|CSV|par)$`
-               temp_table_re    = `#sql-[0-9_]+`
-               part_table_re    = `(.+)#P#p\d+`
-       )
 
        path := t.FILE_NAME
 
+       if cached_result, err := cache.Get(path); err == nil {
+               return cached_result
+       }
+
+       // FIXME and make this work.
+       //      re4 := regexp.MustCompile(re_encoded)
+       //      if m4 := re4.FindStringSubmatch(path); m4 != nil {
+       //              if value, err := strconv.ParseInt(m4[1], 16, 16); err != nil {
+       //                      // missing replace @.... with char(value) in path
+       //
+       //              }
+       //      }
+
        // this should probably be ordered from most expected regexp to least
-       re := regexp.MustCompile(table_file_re)
-       if m1 := re.FindStringSubmatch(path); m1 != nil {
+       if m1 := re_table_file.FindStringSubmatch(path); m1 != nil {
                // we may match temporary tables so check for them
-               re2 := regexp.MustCompile(temp_table_re)
-               if m2 := re2.FindStringSubmatch(m1[2]); m2 != nil {
-                       return "<temp_table>"
+               if m2 := re_temp_table.FindStringSubmatch(m1[2]); m2 != nil {
+                       return cache.Put(path, "<temp_table>")
                }
 
                // we may match partitioned tables so check for them
-               re3 := regexp.MustCompile(part_table_re)
-               if m3 := re3.FindStringSubmatch(m1[2]); m3 != nil {
-                       return m1[1] + "." + m3[1] // <schema>.<table> (less partition info)
+               if m3 := re_part_table.FindStringSubmatch(m1[2]); m3 != nil {
+                       return cache.Put(path, m1[1]+"."+m3[1]) // <schema>.<table> (less partition info)
                }
 
-               return m1[1] + "." + m1[2] // <schema>.<table>
+               return cache.Put(path, m1[1]+"."+m1[2]) // <schema>.<table>
        }
-       if regexp.MustCompile(ibdata_re).MatchString(path) == true {
-               return "<ibdata>"
+       if re_ibdata.MatchString(path) == true {
+               return cache.Put(path, "<ibdata>")
        }
-       if regexp.MustCompile(redo_log_re).MatchString(path) == true {
-               return "<redo_log>"
+       if re_redo_log.MatchString(path) == true {
+               return cache.Put(path, "<redo_log>")
        }
-       if regexp.MustCompile(binlog_re).MatchString(path) == true {
-               return "<binlog>"
+       if re_binlog.MatchString(path) == true {
+               return cache.Put(path, "<binlog>")
        }
-       if regexp.MustCompile(db_opt_re).MatchString(path) == true {
-               return "<db_opt>"
+       if re_db_opt.MatchString(path) == true {
+               return cache.Put(path, "<db_opt>")
        }
-       if regexp.MustCompile(slowlog_re).MatchString(path) == true {
-               return "<slow_log>"
+       if re_slowlog.MatchString(path) == true {
+               return cache.Put(path, "<slow_log>")
        }
-       if regexp.MustCompile(auto_cnf_re).MatchString(path) == true {
-               return "<auto_cnf>"
+       if re_auto_cnf.MatchString(path) == true {
+               return cache.Put(path, "<auto_cnf>")
        }
        // relay logs are a bit complicated. If a full path then easy to
        // identify,but if a relative path we may need to add $datadir,
@@ -256,26 +266,27 @@ func (t file_summary_by_instance_row) simple_name(global_variables map[string]st
                if relay_log[0] != '/' { // relative path
                        relay_log = cleanup_path(global_variables["datadir"] + relay_log) // datadir always ends in /
                }
-               relay_log_re := relay_log + `\.(\d{6}|index)$`
-               if regexp.MustCompile(relay_log_re).MatchString(path) == true {
-                       return "<relay_log>"
+               re_relay_log := relay_log + `\.(\d{6}|index)$`
+               if regexp.MustCompile(re_relay_log).MatchString(path) == true {
+                       return cache.Put(path, "<relay_log>")
                }
        }
-       if regexp.MustCompile(pid_file_re).MatchString(path) == true {
-               return "<pid_file>"
+       if re_pid_file.MatchString(path) == true {
+               return cache.Put(path, "<pid_file>")
        }
-       if regexp.MustCompile(error_msg_re).MatchString(path) == true {
-               return "<errmsg>"
+       if re_error_msg.MatchString(path) == true {
+               return cache.Put(path, "<errmsg>")
        }
-       if regexp.MustCompile(charset_re).MatchString(path) == true {
-               return "<charset>"
+       if re_charset.MatchString(path) == true {
+               return cache.Put(path, "<charset>")
        }
-       return path
+       return cache.Put(path, path)
 }
 
 // Convert the imported "table" to a merged one with merged data.
 // Combine all entries with the same "FILE_NAME" by adding their values.
 func merge_by_table_name(orig file_summary_by_instance_rows, global_variables map[string]string) file_summary_by_instance_rows {
+       start := time.Now()
        t := make(file_summary_by_instance_rows, 0, len(orig))
 
        m := make(map[string]file_summary_by_instance_row)
@@ -305,6 +316,7 @@ func merge_by_table_name(orig file_summary_by_instance_rows, global_variables ma
                t = append(t, row)
        }
 
+       lib.Logger.Println("merge_by_table_name() took:", time.Duration(time.Since(start)).String())
        return t
 }
 
@@ -314,6 +326,7 @@ func merge_by_table_name(orig file_summary_by_instance_rows, global_variables ma
 // - change FILE_NAME into a more descriptive value.
 func select_fsbi_rows(dbh *sql.DB) file_summary_by_instance_rows {
        var t file_summary_by_instance_rows
+       start := time.Now()
 
        sql := "SELECT FILE_NAME, COUNT_STAR, SUM_TIMER_WAIT, COUNT_READ, SUM_TIMER_READ, SUM_NUMBER_OF_BYTES_READ, COUNT_WRITE, SUM_TIMER_WRITE, SUM_NUMBER_OF_BYTES_WRITE, COUNT_MISC, SUM_TIMER_MISC FROM file_summary_by_instance"
 
@@ -334,6 +347,7 @@ func select_fsbi_rows(dbh *sql.DB) file_summary_by_instance_rows {
        if err := rows.Err(); err != nil {
                log.Fatal(err)
        }
+       lib.Logger.Println("select_fsbi_rows() took:", time.Duration(time.Since(start)).String())
 
        return t
 }