uid/model/t_uid/t_uid.go
2022-12-02 17:55:47 +08:00

146 lines
3.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package t_uid
import (
"fmt"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"qoobing.com/gomod/log"
)
type t_uid struct {
F_id int64 `gorm:"column:F_id;primaryKey"` // ID范围id
F_pid int64 `gorm:"column:F_pid"` // ID范围的前一个范围id
F_type string `gorm:"column:F_type"` // ID类型
F_prefix string `gorm:"column:F_prefix"` // ID前缀(type+prefix+range_start唯一)
F_range_start int64 `gorm:"column:F_range_start"` // ID范围的起始id
F_range_length int `gorm:"column:F_range_length"` // ID范围的长度
F_range_owner string `gorm:"column:F_range_owner"` // ID范围的拥有者一般是机器id
F_create_time time.Time `gorm:"column:F_create_time"` // 记录创建时间
F_modify_time time.Time `gorm:"column:F_modify_time"` // 记录更新时间
}
type typeInfo struct {
Name string //type name
RangeLength int //Range length
}
var table string = "t_uid" // id range table name
var typeSupported = map[string]typeInfo{
"SIGNID": typeInfo{
Name: "SIGNID",
RangeLength: 3,
},
"USERID": typeInfo{
Name: "USERID",
RangeLength: 3,
},
}
func Init(tablename string) {
table = tablename
}
func (id *t_uid) TableName() string {
return table
}
func (id *t_uid) BeforeCreate(db *gorm.DB) error {
if id.F_create_time.IsZero() {
id.F_create_time = time.Now()
id.F_modify_time = time.Now()
}
return nil
}
func (id *t_uid) BeforeUpdate(db *gorm.DB) (err error) {
id.F_modify_time = time.Now()
return nil
}
func CreateIdRange(db *gorm.DB, typ, prefix string) (start int64, length int, err error) {
// Step 1. init variables
if t, ok := typeSupported[typ]; !ok {
panic(fmt.Sprintf("id type [%s] not supported yet", typ))
} else {
length = t.RangeLength
}
var (
lock = clause.Locking{Strength: "UPDATE"}
root = t_uid{}
rootcond = map[string]interface{}{
"F_type": fmt.Sprintf("%s#ROOT", typ),
"F_prefix": prefix,
"F_pid": 0,
}
rootattr = map[string]interface{}{
"F_range_start": -length,
"F_range_length": length,
"F_range_owner": "0",
}
selfid = "TODO"
)
log.Infof("start CreateIdRange...")
// Step 2. get lastid && lock root(type+prefix)
var tx = db.Begin()
var txsuccess = false
defer func() {
if !txsuccess {
tx.Rollback()
}
}()
txr := tx.Clauses(lock).
Where(rootcond).
Attrs(rootattr).
FirstOrCreate(&root)
if txr.Error != nil {
return 0, 0, txr.Error
}
if root.F_range_owner == "0" {
// for new created root we set owner to itself.
root.F_range_owner = fmt.Sprintf("%d", root.F_id)
}
log.PrintPretty("root:", root)
// Step 3. insert new range. [can DELETE this for perfermance]
var newrange = t_uid{
F_type: typ,
F_prefix: prefix,
F_range_start: root.F_range_start + int64(length),
F_range_length: length,
F_range_owner: selfid,
}
if n, e := fmt.Sscanf(root.F_range_owner, "%d", &newrange.F_pid); e != nil {
log.Debugf("sscanf F_range_owner(%s) failed: '%s'", root.F_range_owner, e)
return 0, 0, fmt.Errorf("range_owner error")
} else if n != 1 {
log.Debugf("sscanf F_range_owner(%s) failed: n=%d", root.F_range_owner, n)
return 0, 0, fmt.Errorf("range_owner error")
}
if txr := tx.Create(&newrange); txr.Error != nil {
log.PrintPretty("newrange:", newrange)
return 0, 0, txr.Error
}
// Step 4. update root
root.F_range_start = newrange.F_range_start
root.F_range_length = newrange.F_range_length
root.F_range_owner = fmt.Sprintf("%d", newrange.F_id)
if txr := tx.Save(&root); txr.Error != nil {
return 0, 0, txr.Error
}
// Step 5. commit and return
if txr := tx.Commit(); txr.Error != nil {
return 0, 0, txr.Error
}
txsuccess = true
start = newrange.F_range_start
length = newrange.F_range_length
log.Infof("create range success:(%s, %s, %d, %d)", typ, prefix, start, length)
return start, length, nil
}