github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/dsess/database_session_state.go (about) 1 // Copyright 2020 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 dsess 16 17 import ( 18 "strings" 19 20 "github.com/dolthub/go-mysql-server/sql" 21 22 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 23 "github.com/dolthub/dolt/go/libraries/doltcore/env" 24 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/globalstate" 25 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/writer" 26 "github.com/dolthub/dolt/go/libraries/doltcore/table/editor" 27 "github.com/dolthub/dolt/go/libraries/utils/concurrentmap" 28 ) 29 30 // InitialDbState is the initial state of a database, as returned by SessionDatabase.InitialDBState. It is used to 31 // establish the in memory state of the session for every new transaction. 32 type InitialDbState struct { 33 Db sql.Database 34 // WorkingSet is the working set for this database. May be nil for databases tied to a detached root value, in which 35 // case HeadCommit must be set 36 WorkingSet *doltdb.WorkingSet 37 // The head commit for this database. May be nil for databases tied to a detached root value, in which case 38 // RootValue must be set. 39 HeadCommit *doltdb.Commit 40 // HeadRoot is the root value for databases without a HeadCommit. Nil for databases with a HeadCommit. 41 HeadRoot doltdb.RootValue 42 ReadOnly bool 43 DbData env.DbData 44 Remotes *concurrentmap.Map[string, env.Remote] 45 Branches *concurrentmap.Map[string, env.BranchConfig] 46 Backups *concurrentmap.Map[string, env.Remote] 47 48 // If err is set, this InitialDbState is partially invalid, but may be 49 // usable to initialize a database at a revision specifier, for 50 // example. Adding this InitialDbState to a session will return this 51 // error. 52 Err error 53 } 54 55 // SessionDatabase is a database that can be managed by a dsess.Session. It has methods to return its initial state in 56 // order for the session to manage it. 57 type SessionDatabase interface { 58 sql.Database 59 InitialDBState(ctx *sql.Context) (InitialDbState, error) 60 } 61 62 // DatabaseSessionState is the set of all information for a given database in this session. 63 type DatabaseSessionState struct { 64 // dbName is the name of the database this state applies to. This is always the base name of the database, without 65 // a revision qualifier. 66 dbName string 67 // checkedOutRevSpec is the revision of the database when referred to by its base name. Changes only when a 68 // `dolt_checkout` occurs. 69 checkedOutRevSpec string 70 // heads records the in-memory DB state for every branch head accessed by the session 71 heads map[string]*branchState 72 // headCache records the session-caches for every branch head accessed by the session 73 // This is managed separately from the branch states themselves because it persists across transactions (which is 74 // safe because it's keyed by immutable hashes) 75 headCache map[string]*SessionCache 76 // globalState is the global state of this session (shared by all sessions for a particular db) 77 globalState globalstate.GlobalState 78 // tmpFileDir is the directory to use for temporary files for this database 79 tmpFileDir string 80 81 // Same as InitialDbState.Err, this signifies that this 82 // DatabaseSessionState is invalid. LookupDbState returning a 83 // DatabaseSessionState with Err != nil will return that err. 84 Err error 85 } 86 87 func newEmptyDatabaseSessionState() *DatabaseSessionState { 88 return &DatabaseSessionState{ 89 heads: make(map[string]*branchState), 90 headCache: make(map[string]*SessionCache), 91 } 92 } 93 94 // SessionState is the public interface for dealing with session state outside this package. Session-state is always 95 // branch-specific. 96 type SessionState interface { 97 WorkingSet() *doltdb.WorkingSet 98 WorkingRoot() doltdb.RootValue 99 WriteSession() writer.WriteSession 100 EditOpts() editor.Options 101 SessionCache() *SessionCache 102 } 103 104 // branchState records all the in-memory session state for a particular branch head 105 type branchState struct { 106 // dbState is the parent database state for this branch head state 107 dbState *DatabaseSessionState 108 // head is the name of the branch head for this state 109 head string 110 // revisionType is the type of revision this branchState tracks 111 revisionType RevisionType 112 // headCommit is the head commit for this database. May be nil for databases tied to a detached root value, in which 113 // case headRoot must be set. 114 headCommit *doltdb.Commit 115 // HeadRoot is the root value for databases without a headCommit. Nil for databases with a headCommit. 116 headRoot doltdb.RootValue 117 // workingSet is the working set for this database. May be nil for databases tied to a detached root value, in which 118 // case headCommit must be set 119 workingSet *doltdb.WorkingSet 120 // dbData is an accessor for the underlying doltDb 121 dbData env.DbData 122 // writeSession is this head's write session 123 writeSession writer.WriteSession 124 // readOnly is true if this database is read only 125 readOnly bool 126 // dirty is true if this branch state has uncommitted changes 127 dirty bool 128 } 129 130 // NewEmptyBranchState creates a new branch state for the given head name with the head provided, adds it to the db 131 // state, and returns it. The state returned is empty except for its identifiers and must be filled in by the caller. 132 func (dbState *DatabaseSessionState) NewEmptyBranchState(head string, revisionType RevisionType) *branchState { 133 b := &branchState{ 134 dbState: dbState, 135 head: head, 136 revisionType: revisionType, 137 } 138 139 lowerHead := strings.ToLower(head) 140 dbState.heads[lowerHead] = b 141 _, ok := dbState.headCache[lowerHead] 142 if !ok { 143 dbState.headCache[lowerHead] = newSessionCache() 144 } 145 146 return b 147 } 148 149 // RevisionDbName returns the revision-qualified database name for this branch state 150 func (bs *branchState) RevisionDbName() string { 151 return RevisionDbName(bs.dbState.dbName, bs.head) 152 } 153 154 func (bs *branchState) WorkingRoot() doltdb.RootValue { 155 return bs.roots().Working 156 } 157 158 var _ SessionState = (*branchState)(nil) 159 160 func (bs *branchState) WorkingSet() *doltdb.WorkingSet { 161 return bs.workingSet 162 } 163 164 func (bs *branchState) WriteSession() writer.WriteSession { 165 return bs.writeSession 166 } 167 168 func (bs *branchState) SessionCache() *SessionCache { 169 return bs.dbState.headCache[strings.ToLower(bs.head)] 170 } 171 172 func (bs branchState) EditOpts() editor.Options { 173 if bs.writeSession == nil { 174 return editor.Options{} 175 } 176 return bs.WriteSession().GetOptions() 177 } 178 179 func (bs *branchState) roots() doltdb.Roots { 180 if bs.WorkingSet() == nil { 181 return doltdb.Roots{ 182 Head: bs.headRoot, 183 Working: bs.headRoot, 184 Staged: bs.headRoot, 185 } 186 } 187 return doltdb.Roots{ 188 Head: bs.headRoot, 189 Working: bs.WorkingSet().WorkingRoot(), 190 Staged: bs.WorkingSet().StagedRoot(), 191 } 192 }