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  }