github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/meta/autoid/autoid.go (about) 1 // Copyright 2015 PingCAP, 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 autoid 15 16 import ( 17 "math" 18 "sync" 19 "sync/atomic" 20 21 "github.com/insionng/yougam/libraries/juju/errors" 22 "github.com/insionng/yougam/libraries/ngaut/log" 23 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 24 "github.com/insionng/yougam/libraries/pingcap/tidb/meta" 25 "github.com/insionng/yougam/libraries/pingcap/tidb/terror" 26 ) 27 28 const ( 29 step = 10 30 ) 31 32 var errInvalidTableID = terror.ClassAutoid.New(codeInvalidTableID, "invalid TableID") 33 34 // Allocator is an auto increment id generator. 35 // Just keep id unique actually. 36 type Allocator interface { 37 // Alloc allocs the next autoID for table with tableID. 38 // It gets a batch of autoIDs at a time. So it does not need to access storage for each call. 39 Alloc(tableID int64) (int64, error) 40 // Rebase rebases the autoID base for table with tableID and the new base value. 41 // If allocIDs is true, it will allocate some IDs and save to the cache. 42 // If allocIDs is false, it will not allocate IDs. 43 Rebase(tableID, newBase int64, allocIDs bool) error 44 } 45 46 type allocator struct { 47 mu sync.Mutex 48 base int64 49 end int64 50 store kv.Storage 51 dbID int64 52 } 53 54 // Rebase implements autoid.Allocator Rebase interface. 55 func (alloc *allocator) Rebase(tableID, newBase int64, allocIDs bool) error { 56 if tableID == 0 { 57 return errInvalidTableID.Gen("Invalid tableID") 58 } 59 60 alloc.mu.Lock() 61 defer alloc.mu.Unlock() 62 if newBase <= alloc.base { 63 return nil 64 } 65 if newBase <= alloc.end { 66 alloc.base = newBase 67 return nil 68 } 69 70 return kv.RunInNewTxn(alloc.store, true, func(txn kv.Transaction) error { 71 m := meta.NewMeta(txn) 72 end, err := m.GetAutoTableID(alloc.dbID, tableID) 73 if err != nil { 74 return errors.Trace(err) 75 } 76 77 if newBase <= end { 78 return nil 79 } 80 newStep := newBase - end + step 81 if !allocIDs { 82 newStep = newBase - end 83 } 84 end, err = m.GenAutoTableID(alloc.dbID, tableID, newStep) 85 if err != nil { 86 return errors.Trace(err) 87 } 88 89 alloc.end = end 90 alloc.base = newBase 91 if !allocIDs { 92 alloc.base = alloc.end 93 } 94 return nil 95 }) 96 } 97 98 // Alloc implements autoid.Allocator Alloc interface. 99 func (alloc *allocator) Alloc(tableID int64) (int64, error) { 100 if tableID == 0 { 101 return 0, errInvalidTableID.Gen("Invalid tableID") 102 } 103 alloc.mu.Lock() 104 defer alloc.mu.Unlock() 105 if alloc.base == alloc.end { // step 106 err := kv.RunInNewTxn(alloc.store, true, func(txn kv.Transaction) error { 107 m := meta.NewMeta(txn) 108 base, err1 := m.GetAutoTableID(alloc.dbID, tableID) 109 if err1 != nil { 110 return errors.Trace(err1) 111 } 112 end, err1 := m.GenAutoTableID(alloc.dbID, tableID, step) 113 if err1 != nil { 114 return errors.Trace(err1) 115 } 116 117 alloc.end = end 118 if end == step { 119 alloc.base = base 120 } else { 121 alloc.base = end - step 122 } 123 return nil 124 }) 125 126 if err != nil { 127 return 0, errors.Trace(err) 128 } 129 } 130 131 alloc.base++ 132 log.Debugf("[kv] Alloc id %d, table ID:%d, from %p, database ID:%d", alloc.base, tableID, alloc, alloc.dbID) 133 return alloc.base, nil 134 } 135 136 var ( 137 memID int64 138 memIDLock sync.Mutex 139 ) 140 141 type memoryAllocator struct { 142 mu sync.Mutex 143 base int64 144 end int64 145 dbID int64 146 } 147 148 // Rebase implements autoid.Allocator Rebase interface. 149 func (alloc *memoryAllocator) Rebase(tableID, newBase int64, allocIDs bool) error { 150 // TODO: implement it. 151 return nil 152 } 153 154 // Alloc implements autoid.Allocator Alloc interface. 155 func (alloc *memoryAllocator) Alloc(tableID int64) (int64, error) { 156 if tableID == 0 { 157 return 0, errInvalidTableID.Gen("Invalid tableID") 158 } 159 alloc.mu.Lock() 160 defer alloc.mu.Unlock() 161 if alloc.base == alloc.end { // step 162 memIDLock.Lock() 163 memID = memID + step 164 alloc.end = memID 165 alloc.base = alloc.end - step 166 memIDLock.Unlock() 167 } 168 alloc.base++ 169 return alloc.base, nil 170 } 171 172 // NewAllocator returns a new auto increment id generator on the store. 173 func NewAllocator(store kv.Storage, dbID int64) Allocator { 174 return &allocator{ 175 store: store, 176 dbID: dbID, 177 } 178 } 179 180 // NewMemoryAllocator returns a new auto increment id generator in memory. 181 func NewMemoryAllocator(dbID int64) Allocator { 182 return &memoryAllocator{ 183 dbID: dbID, 184 } 185 } 186 187 //autoid error codes. 188 const codeInvalidTableID terror.ErrCode = 1 189 190 var localSchemaID int64 = math.MaxInt64 191 192 // GenLocalSchemaID generates a local schema ID. 193 func GenLocalSchemaID() int64 { 194 return atomic.AddInt64(&localSchemaID, -1) 195 }