github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/table/tables/bounded_tables.go (about)

     1  // Copyright 2016 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 tables
    15  
    16  import (
    17  	"sync/atomic"
    18  	"unsafe"
    19  
    20  	"github.com/insionng/yougam/libraries/juju/errors"
    21  	"github.com/insionng/yougam/libraries/pingcap/tidb/column"
    22  	"github.com/insionng/yougam/libraries/pingcap/tidb/context"
    23  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    24  	"github.com/insionng/yougam/libraries/pingcap/tidb/meta/autoid"
    25  	"github.com/insionng/yougam/libraries/pingcap/tidb/model"
    26  	"github.com/insionng/yougam/libraries/pingcap/tidb/table"
    27  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/types"
    28  )
    29  
    30  const (
    31  	// We want to ensure our initial record id greater than a threshold.
    32  	initialRecordID int64 = 123
    33  	// In our case, a valid record will always greater than 0, so we use a
    34  	// macro to mark an invalid one.
    35  	invalidRecordID int64 = 0
    36  )
    37  
    38  var (
    39  	errOpNotSupported = errors.New("Operation not supported")
    40  )
    41  
    42  type boundedItem struct {
    43  	handle int64
    44  	data   []types.Datum
    45  }
    46  
    47  // BoundedTable implements table.Table interface.
    48  type BoundedTable struct {
    49  	// cursor must be aligned in i386, or we will meet panic when calling atomic.AddInt64
    50  	// https://yougam/libraries/src/sync/atomic/doc.go#L41
    51  	cursor      int64
    52  	ID          int64
    53  	Name        model.CIStr
    54  	Columns     []*column.Col
    55  	pkHandleCol *column.Col
    56  
    57  	recordPrefix kv.Key
    58  	alloc        autoid.Allocator
    59  	meta         *model.TableInfo
    60  
    61  	records  []unsafe.Pointer
    62  	capacity int64
    63  }
    64  
    65  // BoundedTableFromMeta creates a Table instance from model.TableInfo.
    66  func BoundedTableFromMeta(alloc autoid.Allocator, tblInfo *model.TableInfo, capacity int64) table.Table {
    67  	columns := make([]*column.Col, 0, len(tblInfo.Columns))
    68  	var pkHandleColumn *column.Col
    69  	for _, colInfo := range tblInfo.Columns {
    70  		col := &column.Col{ColumnInfo: *colInfo}
    71  		columns = append(columns, col)
    72  		if col.IsPKHandleColumn(tblInfo) {
    73  			pkHandleColumn = col
    74  		}
    75  	}
    76  	t := newBoundedTable(tblInfo.ID, tblInfo.Name.O, columns, alloc, capacity)
    77  	t.pkHandleCol = pkHandleColumn
    78  	t.meta = tblInfo
    79  	return t
    80  }
    81  
    82  // newBoundedTable constructs a BoundedTable instance.
    83  func newBoundedTable(tableID int64, tableName string, cols []*column.Col, alloc autoid.Allocator, capacity int64) *BoundedTable {
    84  	name := model.NewCIStr(tableName)
    85  	t := &BoundedTable{
    86  		ID:           tableID,
    87  		Name:         name,
    88  		alloc:        alloc,
    89  		Columns:      cols,
    90  		recordPrefix: genTableRecordPrefix(tableID),
    91  		records:      make([]unsafe.Pointer, capacity),
    92  		capacity:     capacity,
    93  		cursor:       0,
    94  	}
    95  	return t
    96  }
    97  
    98  // newBoundedItem constructs a boundedItem instance.
    99  func newBoundedItem(handle int64, data []types.Datum) *boundedItem {
   100  	i := &boundedItem{
   101  		handle: handle,
   102  		data:   data,
   103  	}
   104  	return i
   105  }
   106  
   107  // Seek seeks the handle.
   108  func (t *BoundedTable) Seek(ctx context.Context, handle int64) (int64, bool, error) {
   109  	result := (*boundedItem)(nil)
   110  	if handle < invalidRecordID {
   111  		// this is the first seek call.
   112  		result = (*boundedItem)(atomic.LoadPointer(&t.records[0]))
   113  	} else {
   114  		for i := int64(0); i < t.capacity; i++ {
   115  			record := (*boundedItem)(atomic.LoadPointer(&t.records[i]))
   116  			if record == nil {
   117  				break
   118  			}
   119  			if handle == record.handle {
   120  				result = record
   121  				break
   122  			}
   123  		}
   124  	}
   125  	if result == nil {
   126  		// handle not found.
   127  		return invalidRecordID, false, nil
   128  	}
   129  	if result.handle != invalidRecordID {
   130  		// this record is valid.
   131  		return result.handle, true, nil
   132  	}
   133  	// this record is invalid.
   134  	return invalidRecordID, false, nil
   135  }
   136  
   137  // Indices implements table.Table Indices interface.
   138  func (t *BoundedTable) Indices() []*column.IndexedCol {
   139  	return nil
   140  }
   141  
   142  // Meta implements table.Table Meta interface.
   143  func (t *BoundedTable) Meta() *model.TableInfo {
   144  	return t.meta
   145  }
   146  
   147  // Cols implements table.Table Cols interface.
   148  func (t *BoundedTable) Cols() []*column.Col {
   149  	return t.Columns
   150  }
   151  
   152  // RecordPrefix implements table.Table RecordPrefix interface.
   153  func (t *BoundedTable) RecordPrefix() kv.Key {
   154  	return t.recordPrefix
   155  }
   156  
   157  // IndexPrefix implements table.Table IndexPrefix interface.
   158  func (t *BoundedTable) IndexPrefix() kv.Key {
   159  	return nil
   160  }
   161  
   162  // RecordKey implements table.Table RecordKey interface.
   163  func (t *BoundedTable) RecordKey(h int64, col *column.Col) kv.Key {
   164  	colID := int64(0)
   165  	if col != nil {
   166  		colID = col.ID
   167  	}
   168  	return encodeRecordKey(t.recordPrefix, h, colID)
   169  }
   170  
   171  // FirstKey implements table.Table FirstKey interface.
   172  func (t *BoundedTable) FirstKey() kv.Key {
   173  	return t.RecordKey(0, nil)
   174  }
   175  
   176  // Truncate implements table.Table Truncate interface.
   177  func (t *BoundedTable) Truncate(ctx context.Context) error {
   178  	// just reset everything.
   179  	for i := int64(0); i < t.capacity; i++ {
   180  		atomic.StorePointer(&t.records[i], unsafe.Pointer(nil))
   181  	}
   182  	t.cursor = 0
   183  	return nil
   184  }
   185  
   186  // UpdateRecord implements table.Table UpdateRecord interface.
   187  func (t *BoundedTable) UpdateRecord(ctx context.Context, h int64, oldData []types.Datum, newData []types.Datum, touched map[int]bool) error {
   188  	for i := int64(0); i < t.capacity; i++ {
   189  		record := (*boundedItem)(atomic.LoadPointer(&t.records[i]))
   190  		if record == nil {
   191  			// A nil record means consecutive nil records.
   192  			break
   193  		}
   194  		if record.handle == h {
   195  			newRec := newBoundedItem(h, newData)
   196  			atomic.StorePointer(&t.records[i], unsafe.Pointer(newRec))
   197  			break
   198  		}
   199  	}
   200  	// UPDATE always succeeds for BoundedTable.
   201  	return nil
   202  }
   203  
   204  // AddRecord implements table.Table AddRecord interface.
   205  func (t *BoundedTable) AddRecord(ctx context.Context, r []types.Datum) (int64, error) {
   206  	var recordID int64
   207  	var err error
   208  	if t.pkHandleCol != nil {
   209  		recordID, err = types.ToInt64(r[t.pkHandleCol.Offset].GetValue())
   210  		if err != nil {
   211  			return invalidRecordID, errors.Trace(err)
   212  		}
   213  	} else {
   214  		recordID, err = t.alloc.Alloc(t.ID)
   215  		if err != nil {
   216  			return invalidRecordID, errors.Trace(err)
   217  		}
   218  	}
   219  	cursor := atomic.AddInt64(&t.cursor, 1) - 1
   220  	index := int64(cursor % t.capacity)
   221  	record := newBoundedItem(recordID+initialRecordID, r)
   222  	atomic.StorePointer(&t.records[index], unsafe.Pointer(record))
   223  	return recordID + initialRecordID, nil
   224  }
   225  
   226  // RowWithCols implements table.Table RowWithCols interface.
   227  func (t *BoundedTable) RowWithCols(ctx context.Context, h int64, cols []*column.Col) ([]types.Datum, error) {
   228  	row := []types.Datum(nil)
   229  	for i := int64(0); i < t.capacity; i++ {
   230  		record := (*boundedItem)(atomic.LoadPointer(&t.records[i]))
   231  		if record == nil {
   232  			// A nil record means consecutive nil records.
   233  			break
   234  		}
   235  		if record.handle == h {
   236  			row = record.data
   237  			break
   238  		}
   239  	}
   240  	if row == nil {
   241  		return nil, errRowNotFound
   242  	}
   243  	v := make([]types.Datum, len(cols))
   244  	for i, col := range cols {
   245  		if col == nil {
   246  			continue
   247  		}
   248  		v[i] = row[col.Offset]
   249  	}
   250  	return v, nil
   251  }
   252  
   253  // Row implements table.Table Row interface.
   254  func (t *BoundedTable) Row(ctx context.Context, h int64) ([]types.Datum, error) {
   255  	r, err := t.RowWithCols(nil, h, t.Cols())
   256  	if err != nil {
   257  		return nil, errors.Trace(err)
   258  	}
   259  	return r, nil
   260  }
   261  
   262  // LockRow implements table.Table LockRow interface.
   263  func (t *BoundedTable) LockRow(ctx context.Context, h int64, forRead bool) error {
   264  	return nil
   265  }
   266  
   267  // RemoveRecord implements table.Table RemoveRecord interface.
   268  func (t *BoundedTable) RemoveRecord(ctx context.Context, h int64, r []types.Datum) error {
   269  	// not supported, BoundedTable is TRUNCATE only
   270  	return errOpNotSupported
   271  }
   272  
   273  // AllocAutoID implements table.Table AllocAutoID interface.
   274  func (t *BoundedTable) AllocAutoID() (int64, error) {
   275  	recordID, err := t.alloc.Alloc(t.ID)
   276  	if err != nil {
   277  		return invalidRecordID, errors.Trace(err)
   278  	}
   279  	return recordID + initialRecordID, nil
   280  }
   281  
   282  // RebaseAutoID implements table.Table RebaseAutoID interface.
   283  func (t *BoundedTable) RebaseAutoID(newBase int64, isSetStep bool) error {
   284  	return t.alloc.Rebase(t.ID, newBase, isSetStep)
   285  }
   286  
   287  // IterRecords implements table.Table IterRecords interface.
   288  func (t *BoundedTable) IterRecords(ctx context.Context, startKey kv.Key, cols []*column.Col,
   289  	fn table.RecordIterFunc) error {
   290  	return nil
   291  }