github.com/matrixorigin/matrixone@v1.2.0/pkg/bootstrap/versions/upgrade_tenant_task.go (about)

     1  // Copyright 2024 Matrix Origin
     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 versions
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/matrixorigin/matrixone/pkg/catalog"
    21  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    22  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    23  	"github.com/matrixorigin/matrixone/pkg/pb/lock"
    24  	"github.com/matrixorigin/matrixone/pkg/util/executor"
    25  )
    26  
    27  func AddUpgradeTenantTask(
    28  	upgradeID uint64,
    29  	version string,
    30  	fromAccountID int32,
    31  	toAccountID int32,
    32  	txn executor.TxnExecutor) error {
    33  	sql := fmt.Sprintf(`insert into %s (
    34  			upgrade_id, 
    35  			target_version, 
    36  			from_account_id, 
    37  			to_account_id, 
    38  			ready, 
    39  			create_at, 
    40  			update_at) values (%d, '%s', %d, %d, %d, current_timestamp(), current_timestamp())`,
    41  		catalog.MOUpgradeTenantTable,
    42  		upgradeID,
    43  		version,
    44  		fromAccountID,
    45  		toAccountID,
    46  		No)
    47  	res, err := txn.Exec(sql, executor.StatementOption{})
    48  	if err != nil {
    49  		return err
    50  	}
    51  	res.Close()
    52  	return nil
    53  }
    54  
    55  func UpdateUpgradeTenantTaskState(
    56  	taskID uint64,
    57  	state int32,
    58  	txn executor.TxnExecutor) error {
    59  	sql := fmt.Sprintf("update %s set ready = %d where id = %d",
    60  		catalog.MOUpgradeTenantTable,
    61  		state,
    62  		taskID)
    63  	res, err := txn.Exec(sql, executor.StatementOption{})
    64  	if err != nil {
    65  		return err
    66  	}
    67  	res.Close()
    68  	return nil
    69  }
    70  
    71  func GetUpgradeTenantTasks(
    72  	upgradeID uint64,
    73  	txn executor.TxnExecutor) (uint64, []int32, []string, error) {
    74  	taskID := uint64(0)
    75  	tenants := make([]int32, 0)
    76  	versions := make([]string, 0)
    77  	after := int32(0)
    78  	for {
    79  		sql := fmt.Sprintf("select id, from_account_id, to_account_id from %s where from_account_id >= %d and upgrade_id = %d and ready = %d order by id limit 1",
    80  			catalog.MOUpgradeTenantTable,
    81  			after,
    82  			upgradeID,
    83  			No)
    84  		res, err := txn.Exec(sql, executor.StatementOption{})
    85  		if err != nil {
    86  			return 0, nil, nil, err
    87  		}
    88  		from := int32(-1)
    89  		to := int32(-1)
    90  		res.ReadRows(func(rows int, cols []*vector.Vector) bool {
    91  			taskID = vector.GetFixedAt[uint64](cols[0], 0)
    92  			from = vector.GetFixedAt[int32](cols[1], 0)
    93  			to = vector.GetFixedAt[int32](cols[2], 0)
    94  			return true
    95  		})
    96  		res.Close()
    97  		if from == -1 {
    98  			return 0, nil, nil, nil
    99  		}
   100  
   101  		sql = fmt.Sprintf("select account_id, create_version from mo_account where account_id >= %d and account_id <= %d for update",
   102  			from, to)
   103  		res, err = txn.Exec(sql, executor.StatementOption{}.WithWaitPolicy(lock.WaitPolicy_FastFail))
   104  		if err != nil {
   105  			if isConflictError(err) {
   106  				after = to + 1
   107  				continue
   108  			}
   109  			return 0, nil, nil, err
   110  		}
   111  		res.ReadRows(func(rows int, cols []*vector.Vector) bool {
   112  			for i := 0; i < rows; i++ {
   113  				tenants = append(tenants, vector.GetFixedAt[int32](cols[0], i))
   114  				versions = append(versions, cols[1].GetStringAt(i))
   115  			}
   116  			return true
   117  		})
   118  		res.Close()
   119  		return taskID, tenants, versions, nil
   120  	}
   121  }
   122  
   123  func GetTenantCreateVersionForUpdate(
   124  	tenantID int32,
   125  	txn executor.TxnExecutor) (string, error) {
   126  	sql := fmt.Sprintf("select create_version from mo_account where account_id = %d for update", tenantID)
   127  	res, err := txn.Exec(sql, executor.StatementOption{})
   128  	if err != nil {
   129  		return "", err
   130  	}
   131  	defer res.Close()
   132  	version := ""
   133  	res.ReadRows(func(rows int, cols []*vector.Vector) bool {
   134  		version = cols[0].GetStringAt(0)
   135  		return true
   136  	})
   137  	if version == "" {
   138  		panic(fmt.Sprintf("BUG: missing tenant: %d", tenantID))
   139  	}
   140  	return version, nil
   141  }
   142  
   143  func UpgradeTenantVersion(
   144  	tenantID int32,
   145  	version string,
   146  	txn executor.TxnExecutor) error {
   147  	sql := fmt.Sprintf("update mo_account set create_version = '%s' where account_id = %d",
   148  		version,
   149  		tenantID)
   150  	res, err := txn.Exec(sql, executor.StatementOption{})
   151  	if err != nil {
   152  		return err
   153  	}
   154  	defer res.Close()
   155  	if res.AffectedRows != 1 {
   156  		panic(fmt.Sprintf("BUG: update tenant: %d failed with AffectedRows %d",
   157  			tenantID, res.AffectedRows))
   158  	}
   159  	return nil
   160  }
   161  
   162  func isConflictError(err error) bool {
   163  	return moerr.IsMoErrCode(err, moerr.ErrLockConflict)
   164  }
   165  
   166  func GetTenantVersion(
   167  	tenantID int32,
   168  	txn executor.TxnExecutor) (string, error) {
   169  	sql := fmt.Sprintf("select create_version from mo_account where account_id = %d", tenantID)
   170  	res, err := txn.Exec(sql, executor.StatementOption{})
   171  	if err != nil {
   172  		return "", err
   173  	}
   174  	defer res.Close()
   175  	version := ""
   176  	res.ReadRows(func(rows int, cols []*vector.Vector) bool {
   177  		version = cols[0].GetStringAt(0)
   178  		return true
   179  	})
   180  	if version == "" {
   181  		panic(fmt.Sprintf("BUG: missing tenant: %d", tenantID))
   182  	}
   183  	return version, nil
   184  }