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  }