cubefs/master/id_allocator.go
leonrayang 5ae500768b feature: support multi version snapshot
Signed-off-by: leonrayang <chl696@sina.com>
2023-08-30 20:05:32 +08:00

298 lines
8.2 KiB
Go

// Copyright 2018 The CubeFS Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
package master
import (
"fmt"
"math"
"strconv"
"sync"
"sync/atomic"
"github.com/cubefs/cubefs/raftstore"
"github.com/cubefs/cubefs/raftstore/raftstore_db"
"github.com/cubefs/cubefs/util/log"
)
// IDAllocator generates and allocates ids
type IDAllocator struct {
dataPartitionID uint64
metaPartitionID uint64
commonID uint64
clientID uint64
clientIDLimit uint64
quotaID uint32
store *raftstore_db.RocksDBStore
partition raftstore.Partition
dpIDLock sync.RWMutex
mpIDLock sync.RWMutex
mnIDLock sync.RWMutex
qaIDLock sync.RWMutex
}
const clientIDBatchCount = 1000
func newIDAllocator(store *raftstore_db.RocksDBStore, partition raftstore.Partition) (alloc *IDAllocator) {
alloc = new(IDAllocator)
alloc.store = store
alloc.partition = partition
return
}
func (alloc *IDAllocator) restore() {
alloc.restoreMaxDataPartitionID()
alloc.restoreMaxMetaPartitionID()
alloc.restoreMaxCommonID()
alloc.restoreMaxQuotaID()
alloc.restoreClientID()
}
func (alloc *IDAllocator) restoreMaxDataPartitionID() {
value, err := alloc.store.Get(maxDataPartitionIDKey)
if err != nil {
panic(fmt.Sprintf("Failed to restore maxDataPartitionID,err:%v ", err.Error()))
}
bytes := value.([]byte)
if len(bytes) == 0 {
alloc.dataPartitionID = 0
return
}
maxDataPartitionID, err := strconv.ParseUint(string(bytes), 10, 64)
if err != nil {
panic(fmt.Sprintf("Failed to restore maxDataPartitionID,err:%v ", err.Error()))
}
alloc.dataPartitionID = maxDataPartitionID
log.LogInfof("action[restoreMaxDataPartitionID] maxDpID[%v]", alloc.dataPartitionID)
}
func (alloc *IDAllocator) restoreMaxMetaPartitionID() {
value, err := alloc.store.Get(maxMetaPartitionIDKey)
if err != nil {
panic(fmt.Sprintf("Failed to restore maxPartitionID,err:%v ", err.Error()))
}
bytes := value.([]byte)
if len(bytes) == 0 {
alloc.metaPartitionID = 0
return
}
maxPartitionID, err := strconv.ParseUint(string(bytes), 10, 64)
if err != nil {
panic(fmt.Sprintf("Failed to restore maxPartitionID,err:%v ", err.Error()))
}
alloc.metaPartitionID = maxPartitionID
log.LogInfof("action[restoreMaxMetaPartitionID] maxMpID[%v]", alloc.metaPartitionID)
}
// The data node, meta node, and node set share the same ID allocator.
func (alloc *IDAllocator) restoreMaxCommonID() {
value, err := alloc.store.Get(maxCommonIDKey)
if err != nil {
panic(fmt.Sprintf("Failed to restore maxCommonID,err:%v ", err.Error()))
}
bytes := value.([]byte)
if len(bytes) == 0 {
alloc.commonID = 0
return
}
maxMetaNodeID, err := strconv.ParseUint(string(bytes), 10, 64)
if err != nil {
panic(fmt.Sprintf("Failed to restore maxCommonID,err:%v ", err.Error()))
}
alloc.commonID = maxMetaNodeID
log.LogInfof("action[restoreMaxCommonID] maxCommonID[%v]", alloc.commonID)
}
func (alloc *IDAllocator) restoreMaxQuotaID() {
value, err := alloc.store.Get(maxQuotaIDKey)
if err != nil {
panic(fmt.Sprintf("Failed to restore maxQuotaID,err:%v ", err.Error()))
}
bytes := value.([]byte)
if len(bytes) == 0 {
alloc.quotaID = 0
return
}
maxQuotaID, err := strconv.ParseUint(string(bytes), 10, 64)
if err != nil {
panic(fmt.Sprintf("Failed to restore maxQuotaID,err:%v ", err.Error()))
}
if maxQuotaID > 0 && maxQuotaID <= math.MaxInt32 {
alloc.quotaID = uint32(maxQuotaID)
} else {
alloc.quotaID = math.MaxInt32
}
log.LogInfof("action[restoreMaxCommonID] maxQuotaID[%v]", alloc.quotaID)
}
func (alloc *IDAllocator) setDataPartitionID(id uint64) {
atomic.StoreUint64(&alloc.dataPartitionID, id)
}
func (alloc *IDAllocator) setMetaPartitionID(id uint64) {
atomic.StoreUint64(&alloc.metaPartitionID, id)
}
func (alloc *IDAllocator) setCommonID(id uint64) {
atomic.StoreUint64(&alloc.commonID, id)
}
func (alloc *IDAllocator) restoreClientID() {
alloc.mpIDLock.Lock()
defer alloc.mpIDLock.Unlock()
value, err := alloc.store.Get(maxClientIDKey)
if err != nil {
panic(fmt.Sprintf("Failed to restore maxClientID,err:%v ", err.Error()))
}
bytes := value.([]byte)
if len(bytes) != 0 {
alloc.clientID, err = strconv.ParseUint(string(bytes), 10, 64)
if err != nil {
panic(fmt.Sprintf("Failed to restore maxClientID,err:%v ", err.Error()))
}
}
alloc.clientIDLimit = alloc.clientID
alloc.clientID += clientIDBatchCount
}
func (alloc *IDAllocator) setQuotaID(id uint32) {
atomic.StoreUint32(&alloc.quotaID, id)
}
func (alloc *IDAllocator) allocateDataPartitionID() (partitionID uint64, err error) {
alloc.dpIDLock.Lock()
defer alloc.dpIDLock.Unlock()
var cmd []byte
metadata := new(RaftCmd)
partitionID = atomic.LoadUint64(&alloc.dataPartitionID) + 1
metadata.Op = opSyncAllocDataPartitionID
metadata.K = maxDataPartitionIDKey
value := strconv.FormatUint(uint64(partitionID), 10)
metadata.V = []byte(value)
cmd, err = metadata.Marshal()
if err != nil {
goto errHandler
}
if _, err = alloc.partition.Submit(cmd); err != nil {
goto errHandler
}
alloc.setDataPartitionID(partitionID)
return
errHandler:
log.LogErrorf("action[allocateDataPartitionID] err:%v", err.Error())
return
}
func (alloc *IDAllocator) allocateMetaPartitionID() (partitionID uint64, err error) {
alloc.mpIDLock.Lock()
defer alloc.mpIDLock.Unlock()
var cmd []byte
metadata := new(RaftCmd)
metadata.Op = opSyncAllocMetaPartitionID
metadata.K = maxMetaPartitionIDKey
partitionID = atomic.LoadUint64(&alloc.metaPartitionID) + 1
value := strconv.FormatUint(uint64(partitionID), 10)
metadata.V = []byte(value)
cmd, err = metadata.Marshal()
if err != nil {
goto errHandler
}
if _, err = alloc.partition.Submit(cmd); err != nil {
goto errHandler
}
alloc.setMetaPartitionID(partitionID)
return
errHandler:
log.LogErrorf("action[allocateMetaPartitionID] err:%v", err.Error())
return
}
func (alloc *IDAllocator) allocateClientID() (clientID uint64, err error) {
alloc.mpIDLock.Lock()
defer alloc.mpIDLock.Unlock()
clientID = alloc.clientID + 1
if alloc.clientIDLimit < clientID {
var cmd []byte
metadata := new(RaftCmd)
metadata.Op = opSyncAllocClientID
metadata.K = maxClientIDKey
// sync clientID - 1
value := strconv.FormatUint(uint64(alloc.clientID), 10)
metadata.V = []byte(value)
cmd, err = metadata.Marshal()
if err != nil {
goto errHandler
}
if _, err = alloc.partition.Submit(cmd); err != nil {
goto errHandler
}
alloc.clientIDLimit = alloc.clientID + clientIDBatchCount
}
alloc.clientID = clientID
return
errHandler:
log.LogErrorf("action[allocateClientID] err:%v", err.Error())
return
}
func (alloc *IDAllocator) allocateCommonID() (id uint64, err error) {
alloc.mnIDLock.Lock()
defer alloc.mnIDLock.Unlock()
var cmd []byte
metadata := new(RaftCmd)
metadata.Op = opSyncAllocCommonID
metadata.K = maxCommonIDKey
id = atomic.LoadUint64(&alloc.commonID) + 1
value := strconv.FormatUint(uint64(id), 10)
metadata.V = []byte(value)
cmd, err = metadata.Marshal()
if err != nil {
goto errHandler
}
if _, err = alloc.partition.Submit(cmd); err != nil {
goto errHandler
}
alloc.setCommonID(id)
return
errHandler:
log.LogErrorf("action[allocateCommonID] err:%v", err.Error())
return
}
func (alloc *IDAllocator) allocateQuotaID() (id uint32, err error) {
alloc.qaIDLock.Lock()
defer alloc.qaIDLock.Unlock()
var cmd []byte
metadata := new(RaftCmd)
metadata.Op = opSyncAllocQuotaID
metadata.K = maxQuotaIDKey
id = atomic.LoadUint32(&alloc.quotaID) + 1
value := strconv.FormatUint(uint64(id), 10)
metadata.V = []byte(value)
cmd, err = metadata.Marshal()
if err != nil {
goto errHandler
}
if _, err = alloc.partition.Submit(cmd); err != nil {
goto errHandler
}
alloc.setQuotaID(id)
return
errHandler:
log.LogErrorf("action[allocateQuotaID] err:%v", err.Error())
return
}