github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/dprocedures/stats_funcs.go (about) 1 // Copyright 2024 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package dprocedures 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/dolthub/go-mysql-server/sql" 22 gmstypes "github.com/dolthub/go-mysql-server/sql/types" 23 24 "github.com/dolthub/dolt/go/libraries/doltcore/env" 25 "github.com/dolthub/dolt/go/libraries/doltcore/ref" 26 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" 27 ) 28 29 var statsFuncSchema = []*sql.Column{ 30 { 31 Name: "message", 32 Type: gmstypes.LongText, 33 Nullable: true, 34 }, 35 } 36 37 func statsFunc(fn func(ctx *sql.Context) (interface{}, error)) func(ctx *sql.Context, args ...string) (sql.RowIter, error) { 38 return func(ctx *sql.Context, args ...string) (sql.RowIter, error) { 39 res, err := fn(ctx) 40 if err != nil { 41 return nil, err 42 } 43 return rowToIter(res), nil 44 } 45 } 46 47 // AutoRefreshStatsProvider is a sql.StatsProvider that exposes hooks for 48 // observing and manipulating background database auto refresh threads. 49 type AutoRefreshStatsProvider interface { 50 sql.StatsProvider 51 CancelRefreshThread(string) 52 StartRefreshThread(*sql.Context, dsess.DoltDatabaseProvider, string, *env.DoltEnv, dsess.SqlDatabase) error 53 ThreadStatus(string) string 54 } 55 56 // statsRestart tries to stop and then start a refresh thread 57 func statsRestart(ctx *sql.Context) (interface{}, error) { 58 dSess := dsess.DSessFromSess(ctx.Session) 59 statsPro := dSess.StatsProvider() 60 dbName := strings.ToLower(ctx.GetCurrentDatabase()) 61 62 if afp, ok := statsPro.(AutoRefreshStatsProvider); ok { 63 pro := dSess.Provider() 64 newFs, err := pro.FileSystem().WithWorkingDir(dbName) 65 if err != nil { 66 return nil, fmt.Errorf("failed to restart stats collection: %w", err) 67 } 68 69 dEnv := env.Load(ctx, env.GetCurrentUserHomeDir, newFs, pro.DbFactoryUrl(), "TODO") 70 71 sqlDb, ok := pro.BaseDatabase(ctx, dbName) 72 if !ok { 73 return nil, fmt.Errorf("failed to restart stats collection: database not found: %s", dbName) 74 } 75 76 afp.CancelRefreshThread(dbName) 77 78 err = afp.StartRefreshThread(ctx, pro, dbName, dEnv, sqlDb) 79 if err != nil { 80 return nil, fmt.Errorf("failed to restart collection: %w", err) 81 } 82 return fmt.Sprintf("restarted stats collection: %s", ref.StatsRef{}.String()), nil 83 } 84 return nil, fmt.Errorf("provider does not implement AutoRefreshStatsProvider") 85 } 86 87 // statsStatus returns the last update for a stats thread 88 func statsStatus(ctx *sql.Context) (interface{}, error) { 89 dSess := dsess.DSessFromSess(ctx.Session) 90 dbName := strings.ToLower(ctx.GetCurrentDatabase()) 91 pro := dSess.StatsProvider() 92 if afp, ok := pro.(AutoRefreshStatsProvider); ok { 93 return afp.ThreadStatus(dbName), nil 94 } 95 return nil, fmt.Errorf("provider does not implement AutoRefreshStatsProvider") 96 } 97 98 // statsStop cancels a refresh thread 99 func statsStop(ctx *sql.Context) (interface{}, error) { 100 dSess := dsess.DSessFromSess(ctx.Session) 101 statsPro := dSess.StatsProvider() 102 dbName := strings.ToLower(ctx.GetCurrentDatabase()) 103 104 if afp, ok := statsPro.(AutoRefreshStatsProvider); ok { 105 afp.CancelRefreshThread(dbName) 106 return fmt.Sprintf("stopped thread: %s", dbName), nil 107 } 108 return nil, fmt.Errorf("provider does not implement AutoRefreshStatsProvider") 109 } 110 111 // statsDrop deletes the stats ref 112 func statsDrop(ctx *sql.Context) (interface{}, error) { 113 dSess := dsess.DSessFromSess(ctx.Session) 114 pro := dSess.StatsProvider() 115 dbName := strings.ToLower(ctx.GetCurrentDatabase()) 116 117 if afp, ok := pro.(AutoRefreshStatsProvider); ok { 118 // currently unsafe to drop stats while running refresh 119 afp.CancelRefreshThread(dbName) 120 } 121 err := pro.DropDbStats(ctx, dbName, true) 122 if err != nil { 123 return nil, fmt.Errorf("failed to drop stats: %w", err) 124 } 125 return fmt.Sprintf("deleted stats ref for %s", dbName), nil 126 }