github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/schema.go (about) 1 // Copyright 2020 WHTCORPS INC, 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package dbs 15 16 import ( 17 "github.com/whtcorpsinc/errors" 18 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 19 "github.com/whtcorpsinc/milevadb/schemareplicant" 20 "github.com/whtcorpsinc/milevadb/spacetime" 21 ) 22 23 func onCreateSchema(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 24 schemaID := job.SchemaID 25 dbInfo := &perceptron.DBInfo{} 26 if err := job.DecodeArgs(dbInfo); err != nil { 27 // Invalid arguments, cancel this job. 28 job.State = perceptron.JobStateCancelled 29 return ver, errors.Trace(err) 30 } 31 32 dbInfo.ID = schemaID 33 dbInfo.State = perceptron.StateNone 34 35 err := checkSchemaNotExists(d, t, schemaID, dbInfo) 36 if err != nil { 37 if schemareplicant.ErrDatabaseExists.Equal(err) { 38 // The database already exists, can't create it, we should cancel this job now. 39 job.State = perceptron.JobStateCancelled 40 } 41 return ver, errors.Trace(err) 42 } 43 44 ver, err = uFIDelateSchemaVersion(t, job) 45 if err != nil { 46 return ver, errors.Trace(err) 47 } 48 49 switch dbInfo.State { 50 case perceptron.StateNone: 51 // none -> public 52 dbInfo.State = perceptron.StatePublic 53 err = t.CreateDatabase(dbInfo) 54 if err != nil { 55 return ver, errors.Trace(err) 56 } 57 // Finish this job. 58 job.FinishDBJob(perceptron.JobStateDone, perceptron.StatePublic, ver, dbInfo) 59 return ver, nil 60 default: 61 // We can't enter here. 62 return ver, errors.Errorf("invalid EDB state %v", dbInfo.State) 63 } 64 } 65 66 func checkSchemaNotExists(d *dbsCtx, t *spacetime.Meta, schemaID int64, dbInfo *perceptron.DBInfo) error { 67 // d.infoHandle maybe nil in some test. 68 if d.infoHandle == nil { 69 return checkSchemaNotExistsFromStore(t, schemaID, dbInfo) 70 } 71 // Try to use memory schemaReplicant info to check first. 72 currVer, err := t.GetSchemaVersion() 73 if err != nil { 74 return err 75 } 76 is := d.infoHandle.Get() 77 if is.SchemaMetaVersion() == currVer { 78 return checkSchemaNotExistsFromSchemaReplicant(is, schemaID, dbInfo) 79 } 80 return checkSchemaNotExistsFromStore(t, schemaID, dbInfo) 81 } 82 83 func checkSchemaNotExistsFromSchemaReplicant(is schemareplicant.SchemaReplicant, schemaID int64, dbInfo *perceptron.DBInfo) error { 84 // Check database exists by name. 85 if is.SchemaExists(dbInfo.Name) { 86 return schemareplicant.ErrDatabaseExists.GenWithStackByArgs(dbInfo.Name) 87 } 88 // Check database exists by ID. 89 if _, ok := is.SchemaByID(schemaID); ok { 90 return schemareplicant.ErrDatabaseExists.GenWithStackByArgs(dbInfo.Name) 91 } 92 return nil 93 } 94 95 func checkSchemaNotExistsFromStore(t *spacetime.Meta, schemaID int64, dbInfo *perceptron.DBInfo) error { 96 dbs, err := t.ListDatabases() 97 if err != nil { 98 return errors.Trace(err) 99 } 100 101 for _, EDB := range dbs { 102 if EDB.Name.L == dbInfo.Name.L { 103 if EDB.ID != schemaID { 104 return schemareplicant.ErrDatabaseExists.GenWithStackByArgs(EDB.Name) 105 } 106 dbInfo = EDB 107 } 108 } 109 return nil 110 } 111 112 func onModifySchemaCharsetAndDefCauslate(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 113 var toCharset, toDefCauslate string 114 if err := job.DecodeArgs(&toCharset, &toDefCauslate); err != nil { 115 job.State = perceptron.JobStateCancelled 116 return ver, errors.Trace(err) 117 } 118 119 dbInfo, err := checkSchemaExistAndCancelNotExistJob(t, job) 120 if err != nil { 121 return ver, errors.Trace(err) 122 } 123 124 if dbInfo.Charset == toCharset && dbInfo.DefCauslate == toDefCauslate { 125 job.FinishDBJob(perceptron.JobStateDone, perceptron.StatePublic, ver, dbInfo) 126 return ver, nil 127 } 128 129 dbInfo.Charset = toCharset 130 dbInfo.DefCauslate = toDefCauslate 131 132 if err = t.UFIDelateDatabase(dbInfo); err != nil { 133 return ver, errors.Trace(err) 134 } 135 if ver, err = uFIDelateSchemaVersion(t, job); err != nil { 136 return ver, errors.Trace(err) 137 } 138 job.FinishDBJob(perceptron.JobStateDone, perceptron.StatePublic, ver, dbInfo) 139 return ver, nil 140 } 141 142 func onDropSchema(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 143 dbInfo, err := checkSchemaExistAndCancelNotExistJob(t, job) 144 if err != nil { 145 return ver, errors.Trace(err) 146 } 147 148 ver, err = uFIDelateSchemaVersion(t, job) 149 if err != nil { 150 return ver, errors.Trace(err) 151 } 152 switch dbInfo.State { 153 case perceptron.StatePublic: 154 // public -> write only 155 job.SchemaState = perceptron.StateWriteOnly 156 dbInfo.State = perceptron.StateWriteOnly 157 err = t.UFIDelateDatabase(dbInfo) 158 case perceptron.StateWriteOnly: 159 // write only -> delete only 160 job.SchemaState = perceptron.StateDeleteOnly 161 dbInfo.State = perceptron.StateDeleteOnly 162 err = t.UFIDelateDatabase(dbInfo) 163 case perceptron.StateDeleteOnly: 164 dbInfo.State = perceptron.StateNone 165 var blocks []*perceptron.BlockInfo 166 blocks, err = t.ListBlocks(job.SchemaID) 167 if err != nil { 168 return ver, errors.Trace(err) 169 } 170 171 err = t.UFIDelateDatabase(dbInfo) 172 if err != nil { 173 return ver, errors.Trace(err) 174 } 175 if err = t.DroFIDelatabase(dbInfo.ID); err != nil { 176 break 177 } 178 179 // Finish this job. 180 if len(blocks) > 0 { 181 job.Args = append(job.Args, getIDs(blocks)) 182 } 183 job.FinishDBJob(perceptron.JobStateDone, perceptron.StateNone, ver, dbInfo) 184 default: 185 // We can't enter here. 186 err = errors.Errorf("invalid EDB state %v", dbInfo.State) 187 } 188 189 return ver, errors.Trace(err) 190 } 191 192 func checkSchemaExistAndCancelNotExistJob(t *spacetime.Meta, job *perceptron.Job) (*perceptron.DBInfo, error) { 193 dbInfo, err := t.GetDatabase(job.SchemaID) 194 if err != nil { 195 return nil, errors.Trace(err) 196 } 197 if dbInfo == nil { 198 job.State = perceptron.JobStateCancelled 199 return nil, schemareplicant.ErrDatabaseDropExists.GenWithStackByArgs("") 200 } 201 return dbInfo, nil 202 } 203 204 func getIDs(blocks []*perceptron.BlockInfo) []int64 { 205 ids := make([]int64, 0, len(blocks)) 206 for _, t := range blocks { 207 ids = append(ids, t.ID) 208 if t.GetPartitionInfo() != nil { 209 ids = append(ids, getPartitionIDs(t)...) 210 } 211 } 212 213 return ids 214 }