You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
4.2 KiB

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