mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 08:21:11 +00:00 
			
		
		
		
	Integrate public as bindata optionally (#293)
* Dropped unused codekit config * Integrated dynamic and static bindata for public * Ignore public bindata * Add a general generate make task * Integrated flexible public assets into web command * Updated vendoring, added all missiong govendor deps * Made the linter happy with the bindata and dynamic code * Moved public bindata definition to modules directory * Ignoring the new bindata path now * Updated to the new public modules import path * Updated public bindata command and drop the new prefix
This commit is contained in:
		
					parent
					
						
							
								4680c349dd
							
						
					
				
			
			
				commit
				
					
						b6a95a8cb3
					
				
			
		
					 691 changed files with 305318 additions and 1272 deletions
				
			
		
							
								
								
									
										452
									
								
								vendor/github.com/pingcap/tidb/inspectkv/inspectkv.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										452
									
								
								vendor/github.com/pingcap/tidb/inspectkv/inspectkv.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,452 @@
 | 
			
		|||
// Copyright 2015 PingCAP, Inc.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
package inspectkv
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"reflect"
 | 
			
		||||
 | 
			
		||||
	"github.com/juju/errors"
 | 
			
		||||
	"github.com/ngaut/log"
 | 
			
		||||
	"github.com/pingcap/tidb/column"
 | 
			
		||||
	"github.com/pingcap/tidb/kv"
 | 
			
		||||
	"github.com/pingcap/tidb/meta"
 | 
			
		||||
	"github.com/pingcap/tidb/model"
 | 
			
		||||
	"github.com/pingcap/tidb/table"
 | 
			
		||||
	"github.com/pingcap/tidb/table/tables"
 | 
			
		||||
	"github.com/pingcap/tidb/terror"
 | 
			
		||||
	"github.com/pingcap/tidb/util"
 | 
			
		||||
	"github.com/pingcap/tidb/util/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DDLInfo is for DDL information.
 | 
			
		||||
type DDLInfo struct {
 | 
			
		||||
	SchemaVer   int64
 | 
			
		||||
	ReorgHandle int64 // it's only used for DDL information.
 | 
			
		||||
	Owner       *model.Owner
 | 
			
		||||
	Job         *model.Job
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetDDLInfo returns DDL information.
 | 
			
		||||
func GetDDLInfo(txn kv.Transaction) (*DDLInfo, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	info := &DDLInfo{}
 | 
			
		||||
	t := meta.NewMeta(txn)
 | 
			
		||||
 | 
			
		||||
	info.Owner, err = t.GetDDLJobOwner()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
	info.Job, err = t.GetDDLJob(0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
	info.SchemaVer, err = t.GetSchemaVersion()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
	if info.Job == nil {
 | 
			
		||||
		return info, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info.ReorgHandle, err = t.GetDDLReorgHandle(info.Job)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return info, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetBgDDLInfo returns background DDL information.
 | 
			
		||||
func GetBgDDLInfo(txn kv.Transaction) (*DDLInfo, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	info := &DDLInfo{}
 | 
			
		||||
	t := meta.NewMeta(txn)
 | 
			
		||||
 | 
			
		||||
	info.Owner, err = t.GetBgJobOwner()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
	info.Job, err = t.GetBgJob(0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
	info.SchemaVer, err = t.GetSchemaVersion()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return info, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func nextIndexVals(data []types.Datum) []types.Datum {
 | 
			
		||||
	// Add 0x0 to the end of data.
 | 
			
		||||
	return append(data, types.Datum{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RecordData is the record data composed of a handle and values.
 | 
			
		||||
type RecordData struct {
 | 
			
		||||
	Handle int64
 | 
			
		||||
	Values []types.Datum
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetIndexRecordsCount returns the total number of the index records from startVals.
 | 
			
		||||
// If startVals = nil, returns the total number of the index records.
 | 
			
		||||
func GetIndexRecordsCount(txn kv.Transaction, kvIndex kv.Index, startVals []types.Datum) (int64, error) {
 | 
			
		||||
	it, _, err := kvIndex.Seek(txn, startVals)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer it.Close()
 | 
			
		||||
 | 
			
		||||
	var cnt int64
 | 
			
		||||
	for {
 | 
			
		||||
		_, _, err := it.Next()
 | 
			
		||||
		if terror.ErrorEqual(err, io.EOF) {
 | 
			
		||||
			break
 | 
			
		||||
		} else if err != nil {
 | 
			
		||||
			return 0, errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
		cnt++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cnt, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ScanIndexData scans the index handles and values in a limited number, according to the index information.
 | 
			
		||||
// It returns data and the next startVals until it doesn't have data, then returns data is nil and
 | 
			
		||||
// the next startVals is the values which can't get data. If startVals = nil and limit = -1,
 | 
			
		||||
// it returns the index data of the whole.
 | 
			
		||||
func ScanIndexData(txn kv.Transaction, kvIndex kv.Index, startVals []types.Datum, limit int64) (
 | 
			
		||||
	[]*RecordData, []types.Datum, error) {
 | 
			
		||||
	it, _, err := kvIndex.Seek(txn, startVals)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer it.Close()
 | 
			
		||||
 | 
			
		||||
	var idxRows []*RecordData
 | 
			
		||||
	var curVals []types.Datum
 | 
			
		||||
	for limit != 0 {
 | 
			
		||||
		val, h, err1 := it.Next()
 | 
			
		||||
		if terror.ErrorEqual(err1, io.EOF) {
 | 
			
		||||
			return idxRows, nextIndexVals(curVals), nil
 | 
			
		||||
		} else if err1 != nil {
 | 
			
		||||
			return nil, nil, errors.Trace(err1)
 | 
			
		||||
		}
 | 
			
		||||
		idxRows = append(idxRows, &RecordData{Handle: h, Values: val})
 | 
			
		||||
		limit--
 | 
			
		||||
		curVals = val
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nextVals, _, err := it.Next()
 | 
			
		||||
	if terror.ErrorEqual(err, io.EOF) {
 | 
			
		||||
		return idxRows, nextIndexVals(curVals), nil
 | 
			
		||||
	} else if err != nil {
 | 
			
		||||
		return nil, nil, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return idxRows, nextVals, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CompareIndexData compares index data one by one.
 | 
			
		||||
// It returns nil if the data from the index is equal to the data from the table columns,
 | 
			
		||||
// otherwise it returns an error with a different set of records.
 | 
			
		||||
func CompareIndexData(txn kv.Transaction, t table.Table, idx *column.IndexedCol) error {
 | 
			
		||||
	err := checkIndexAndRecord(txn, t, idx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return checkRecordAndIndex(txn, t, idx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkIndexAndRecord(txn kv.Transaction, t table.Table, idx *column.IndexedCol) error {
 | 
			
		||||
	kvIndex := kv.NewKVIndex(t.IndexPrefix(), idx.Name.L, idx.ID, idx.Unique)
 | 
			
		||||
	it, err := kvIndex.SeekFirst(txn)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer it.Close()
 | 
			
		||||
 | 
			
		||||
	cols := make([]*column.Col, len(idx.Columns))
 | 
			
		||||
	for i, col := range idx.Columns {
 | 
			
		||||
		cols[i] = t.Cols()[col.Offset]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		vals1, h, err := it.Next()
 | 
			
		||||
		if terror.ErrorEqual(err, io.EOF) {
 | 
			
		||||
			break
 | 
			
		||||
		} else if err != nil {
 | 
			
		||||
			return errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		vals2, err := rowWithCols(txn, t, h, cols)
 | 
			
		||||
		if terror.ErrorEqual(err, kv.ErrNotExist) {
 | 
			
		||||
			record := &RecordData{Handle: h, Values: vals1}
 | 
			
		||||
			err = errors.Errorf("index:%v != record:%v", record, nil)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
		if !reflect.DeepEqual(vals1, vals2) {
 | 
			
		||||
			record1 := &RecordData{Handle: h, Values: vals1}
 | 
			
		||||
			record2 := &RecordData{Handle: h, Values: vals2}
 | 
			
		||||
			return errors.Errorf("index:%v != record:%v", record1, record2)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkRecordAndIndex(txn kv.Transaction, t table.Table, idx *column.IndexedCol) error {
 | 
			
		||||
	cols := make([]*column.Col, len(idx.Columns))
 | 
			
		||||
	for i, col := range idx.Columns {
 | 
			
		||||
		cols[i] = t.Cols()[col.Offset]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	startKey := t.RecordKey(0, nil)
 | 
			
		||||
	kvIndex := kv.NewKVIndex(t.IndexPrefix(), idx.Name.L, idx.ID, idx.Unique)
 | 
			
		||||
	filterFunc := func(h1 int64, vals1 []types.Datum, cols []*column.Col) (bool, error) {
 | 
			
		||||
		isExist, h2, err := kvIndex.Exist(txn, vals1, h1)
 | 
			
		||||
		if terror.ErrorEqual(err, kv.ErrKeyExists) {
 | 
			
		||||
			record1 := &RecordData{Handle: h1, Values: vals1}
 | 
			
		||||
			record2 := &RecordData{Handle: h2, Values: vals1}
 | 
			
		||||
			return false, errors.Errorf("index:%v != record:%v", record2, record1)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
		if !isExist {
 | 
			
		||||
			record := &RecordData{Handle: h1, Values: vals1}
 | 
			
		||||
			return false, errors.Errorf("index:%v != record:%v", nil, record)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
	err := iterRecords(txn, t, startKey, cols, filterFunc)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func scanTableData(retriever kv.Retriever, t table.Table, cols []*column.Col, startHandle, limit int64) (
 | 
			
		||||
	[]*RecordData, int64, error) {
 | 
			
		||||
	var records []*RecordData
 | 
			
		||||
 | 
			
		||||
	startKey := t.RecordKey(startHandle, nil)
 | 
			
		||||
	filterFunc := func(h int64, d []types.Datum, cols []*column.Col) (bool, error) {
 | 
			
		||||
		if limit != 0 {
 | 
			
		||||
			r := &RecordData{
 | 
			
		||||
				Handle: h,
 | 
			
		||||
				Values: d,
 | 
			
		||||
			}
 | 
			
		||||
			records = append(records, r)
 | 
			
		||||
			limit--
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	err := iterRecords(retriever, t, startKey, cols, filterFunc)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, 0, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(records) == 0 {
 | 
			
		||||
		return records, startHandle, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nextHandle := records[len(records)-1].Handle + 1
 | 
			
		||||
 | 
			
		||||
	return records, nextHandle, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ScanTableRecord scans table row handles and column values in a limited number.
 | 
			
		||||
// It returns data and the next startHandle until it doesn't have data, then returns data is nil and
 | 
			
		||||
// the next startHandle is the handle which can't get data. If startHandle = 0 and limit = -1,
 | 
			
		||||
// it returns the table data of the whole.
 | 
			
		||||
func ScanTableRecord(retriever kv.Retriever, t table.Table, startHandle, limit int64) (
 | 
			
		||||
	[]*RecordData, int64, error) {
 | 
			
		||||
	return scanTableData(retriever, t, t.Cols(), startHandle, limit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ScanSnapshotTableRecord scans the ver version of the table data in a limited number.
 | 
			
		||||
// It returns data and the next startHandle until it doesn't have data, then returns data is nil and
 | 
			
		||||
// the next startHandle is the handle which can't get data. If startHandle = 0 and limit = -1,
 | 
			
		||||
// it returns the table data of the whole.
 | 
			
		||||
func ScanSnapshotTableRecord(store kv.Storage, ver kv.Version, t table.Table, startHandle, limit int64) (
 | 
			
		||||
	[]*RecordData, int64, error) {
 | 
			
		||||
	snap, err := store.GetSnapshot(ver)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, 0, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer snap.Release()
 | 
			
		||||
 | 
			
		||||
	records, nextHandle, err := ScanTableRecord(snap, t, startHandle, limit)
 | 
			
		||||
 | 
			
		||||
	return records, nextHandle, errors.Trace(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CompareTableRecord compares data and the corresponding table data one by one.
 | 
			
		||||
// It returns nil if data is equal to the data that scans from table, otherwise
 | 
			
		||||
// it returns an error with a different set of records. If exact is false, only compares handle.
 | 
			
		||||
func CompareTableRecord(txn kv.Transaction, t table.Table, data []*RecordData, exact bool) error {
 | 
			
		||||
	m := make(map[int64][]types.Datum, len(data))
 | 
			
		||||
	for _, r := range data {
 | 
			
		||||
		if _, ok := m[r.Handle]; ok {
 | 
			
		||||
			return errors.Errorf("handle:%d is repeated in data", r.Handle)
 | 
			
		||||
		}
 | 
			
		||||
		m[r.Handle] = r.Values
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	startKey := t.RecordKey(0, nil)
 | 
			
		||||
	filterFunc := func(h int64, vals []types.Datum, cols []*column.Col) (bool, error) {
 | 
			
		||||
		vals2, ok := m[h]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			record := &RecordData{Handle: h, Values: vals}
 | 
			
		||||
			return false, errors.Errorf("data:%v != record:%v", nil, record)
 | 
			
		||||
		}
 | 
			
		||||
		if !exact {
 | 
			
		||||
			delete(m, h)
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !reflect.DeepEqual(vals, vals2) {
 | 
			
		||||
			record1 := &RecordData{Handle: h, Values: vals2}
 | 
			
		||||
			record2 := &RecordData{Handle: h, Values: vals}
 | 
			
		||||
			return false, errors.Errorf("data:%v != record:%v", record1, record2)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		delete(m, h)
 | 
			
		||||
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
	err := iterRecords(txn, t, startKey, t.Cols(), filterFunc)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for h, vals := range m {
 | 
			
		||||
		record := &RecordData{Handle: h, Values: vals}
 | 
			
		||||
		return errors.Errorf("data:%v != record:%v", record, nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTableRecordsCount returns the total number of table records from startHandle.
 | 
			
		||||
// If startHandle = 0, returns the total number of table records.
 | 
			
		||||
func GetTableRecordsCount(txn kv.Transaction, t table.Table, startHandle int64) (int64, error) {
 | 
			
		||||
	startKey := t.RecordKey(startHandle, nil)
 | 
			
		||||
	it, err := txn.Seek(startKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var cnt int64
 | 
			
		||||
	prefix := t.RecordPrefix()
 | 
			
		||||
	for it.Valid() && it.Key().HasPrefix(prefix) {
 | 
			
		||||
		handle, err := tables.DecodeRecordKeyHandle(it.Key())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		it.Close()
 | 
			
		||||
		rk := t.RecordKey(handle+1, nil)
 | 
			
		||||
		it, err = txn.Seek(rk)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cnt++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	it.Close()
 | 
			
		||||
 | 
			
		||||
	return cnt, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rowWithCols(txn kv.Retriever, t table.Table, h int64, cols []*column.Col) ([]types.Datum, error) {
 | 
			
		||||
	v := make([]types.Datum, len(cols))
 | 
			
		||||
	for i, col := range cols {
 | 
			
		||||
		if col.State != model.StatePublic {
 | 
			
		||||
			return nil, errors.Errorf("Cannot use none public column - %v", cols)
 | 
			
		||||
		}
 | 
			
		||||
		if col.IsPKHandleColumn(t.Meta()) {
 | 
			
		||||
			v[i].SetInt64(h)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		k := t.RecordKey(h, col)
 | 
			
		||||
		data, err := txn.Get(k)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		val, err := tables.DecodeValue(data, &col.FieldType)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
		v[i] = val
 | 
			
		||||
	}
 | 
			
		||||
	return v, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func iterRecords(retriever kv.Retriever, t table.Table, startKey kv.Key, cols []*column.Col,
 | 
			
		||||
	fn table.RecordIterFunc) error {
 | 
			
		||||
	it, err := retriever.Seek(startKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Trace(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer it.Close()
 | 
			
		||||
 | 
			
		||||
	if !it.Valid() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Debugf("startKey:%q, key:%q, value:%q", startKey, it.Key(), it.Value())
 | 
			
		||||
 | 
			
		||||
	prefix := t.RecordPrefix()
 | 
			
		||||
	for it.Valid() && it.Key().HasPrefix(prefix) {
 | 
			
		||||
		// first kv pair is row lock information.
 | 
			
		||||
		// TODO: check valid lock
 | 
			
		||||
		// get row handle
 | 
			
		||||
		handle, err := tables.DecodeRecordKeyHandle(it.Key())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		data, err := rowWithCols(retriever, t, handle, cols)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
		more, err := fn(handle, data, cols)
 | 
			
		||||
		if !more || err != nil {
 | 
			
		||||
			return errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rk := t.RecordKey(handle, nil)
 | 
			
		||||
		err = kv.NextUntil(it, util.RowKeyPrefixFilter(rk))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Trace(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue