github.com/turingchain2020/turingchain@v1.1.21/common/db/table/join.go (about)

     1  package table
     2  
     3  import (
     4  	"errors"
     5  	"strings"
     6  
     7  	"github.com/turingchain2020/turingchain/common/db"
     8  	"github.com/turingchain2020/turingchain/common/log/log15"
     9  	"github.com/turingchain2020/turingchain/types"
    10  	"github.com/turingchain2020/turingchain/util"
    11  )
    12  
    13  var tablelog = log15.New("module", "db.table")
    14  
    15  /*
    16  设计表的联查:
    17  
    18  我们不可能做到数据库这样强大的功能,但是联查功能几乎是不可能绕过的功能。
    19  
    20  table1:
    21  
    22  [gameId, status]
    23  
    24  table2:
    25  [txhash, gameId, addr]
    26  
    27  他们都独立的构造, 与更新
    28  
    29  如果设置了两个表的: join, 比如: addr & status 要作为一个查询key, 那么我们需要维护一个:
    30  
    31  join_table2_table1:
    32  //table2 primary key
    33  //table1 primary key
    34  //addr_status 的一个关联index
    35  [txhash, gameId, addr_status]
    36  
    37  能够join的前提:
    38  table2 包含 table1 的primary key
    39  
    40  数据更新:
    41  table1 数据更新 自动触发: join_table2_table1 更新 addr & status
    42  table2 数据更新 也会自动触发: join_table2_table1 更新 addr & status
    43  
    44  例子:
    45  
    46  table1 更新了 gameId 对应 status -> 触发 join_table2_table1 所有对应 gameId 更新 addr & status
    47  table2 更新了 txhash 对应的 addr -> 触发 join_table2_table1 所有对应的 txhash 对应的 addr & status
    48  
    49  注意 join_table2_table1 是自动维护的
    50  
    51  table2 中自动可以查询 addr & status 这个index
    52  */
    53  
    54  //JoinTable 是由两个表格组合成的一个表格,自动维护一个联合结构
    55  //其中主表: LeftTable
    56  //连接表: RightTable
    57  type JoinTable struct {
    58  	left  *Table
    59  	right *Table
    60  	*Table
    61  	Fk         string
    62  	leftIndex  []string
    63  	rightIndex []string
    64  }
    65  
    66  //NewJoinTable 新建一个JoinTable
    67  func NewJoinTable(left *Table, right *Table, indexes []string) (*JoinTable, error) {
    68  	if left.kvdb != right.kvdb {
    69  		return nil, errors.New("jointable: kvdb must same")
    70  	}
    71  	if _, ok := left.kvdb.(db.KVDB); !ok {
    72  		return nil, errors.New("jointable: kvdb must be db.KVDB")
    73  	}
    74  	if left.opt.Prefix != right.opt.Prefix {
    75  		return nil, errors.New("jointable: left and right table prefix must same")
    76  	}
    77  	fk := right.opt.Primary
    78  	if !left.canGet(fk) {
    79  		return nil, errors.New("jointable: left must has right primary index")
    80  	}
    81  	join := &JoinTable{left: left, right: right, Fk: fk}
    82  	for _, index := range indexes {
    83  		joinindex := strings.Split(index, joinsep)
    84  		if len(joinindex) != 2 {
    85  			return nil, errors.New("jointable: index config error")
    86  		}
    87  		if joinindex[0] != "" && !left.canGet(joinindex[0]) {
    88  			return nil, errors.New("jointable: left table can not get: " + joinindex[0])
    89  		}
    90  		if joinindex[0] != "" {
    91  			join.leftIndex = append(join.leftIndex, joinindex[0])
    92  		}
    93  		if joinindex[1] == "" || !right.canGet(joinindex[1]) {
    94  			return nil, errors.New("jointable: right table can not get: " + joinindex[1])
    95  		}
    96  		if joinindex[1] != "" {
    97  			join.rightIndex = append(join.rightIndex, joinindex[1])
    98  		}
    99  	}
   100  	opt := &Option{
   101  		Join:    true,
   102  		Prefix:  left.opt.Prefix,
   103  		Name:    left.opt.Name + joinsep + right.opt.Name,
   104  		Primary: left.opt.Primary,
   105  		Index:   indexes,
   106  	}
   107  	mytable, err := NewTable(&JoinMeta{
   108  		left:  left.meta,
   109  		right: right.meta}, left.kvdb, opt)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	join.Table = mytable
   114  	return join, nil
   115  }
   116  
   117  //GetLeft get left table
   118  func (join *JoinTable) GetLeft() *Table {
   119  	return join.left
   120  }
   121  
   122  //GetRight get right table
   123  func (join *JoinTable) GetRight() *Table {
   124  	return join.right
   125  }
   126  
   127  //GetTable get table by name
   128  func (join *JoinTable) GetTable(name string) (*Table, error) {
   129  	if join.left.opt.Name == name {
   130  		return join.left, nil
   131  	}
   132  	if join.right.opt.Name == name {
   133  		return join.right, nil
   134  	}
   135  	return nil, types.ErrNotFound
   136  }
   137  
   138  //MustGetTable if name not exist, panic
   139  func (join *JoinTable) MustGetTable(name string) *Table {
   140  	table, err := join.GetTable(name)
   141  	if err != nil {
   142  		panic(err)
   143  	}
   144  	return table
   145  }
   146  
   147  //GetData rewrite get data of jointable
   148  func (join *JoinTable) GetData(primaryKey []byte) (*Row, error) {
   149  	leftrow, err := join.left.GetData(primaryKey)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	rightprimary, err := join.left.index(leftrow, join.Fk)
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  	rightrow, err := join.right.GetData(rightprimary)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	rowjoin := join.meta.CreateRow()
   162  	rowjoin.Ty = None
   163  	rowjoin.Primary = leftrow.Primary
   164  	rowjoin.Data.(*JoinData).Left = leftrow.Data
   165  	rowjoin.Data.(*JoinData).Right = rightrow.Data
   166  	return rowjoin, nil
   167  }
   168  
   169  //ListIndex 查询jointable 数据
   170  func (join *JoinTable) ListIndex(indexName string, prefix []byte, primaryKey []byte, count, direction int32) (rows []*Row, err error) {
   171  	if !strings.Contains(indexName, joinsep) || !join.canGet(indexName) {
   172  		return nil, errors.New("joinable query: indexName must be join index")
   173  	}
   174  	query := &Query{table: join, kvdb: join.left.kvdb.(db.KVDB)}
   175  	return query.ListIndex(indexName, prefix, primaryKey, count, direction)
   176  }
   177  
   178  //Save 重写默认的save 函数,不仅仅 Save left,right table
   179  //还要save jointable
   180  //没有update 到情况,只有del, add, 性能考虑可以加上 update 的情况
   181  //目前update 是通过 del + add 完成
   182  //left modify: del index, add new index (query right by primary) (check in cache)
   183  //right modify: query all primary in left, include in cache, del index, add new index
   184  //TODO: 没有修改过的数据不需要修改
   185  func (join *JoinTable) Save() (kvs []*types.KeyValue, err error) {
   186  	for _, row := range join.left.rows {
   187  		if row.Ty == None {
   188  			continue
   189  		}
   190  		err := join.saveLeft(row)
   191  		if err != nil {
   192  			return nil, err
   193  		}
   194  	}
   195  	for _, row := range join.right.rows {
   196  		if row.Ty == None {
   197  			continue
   198  		}
   199  		err := join.saveRight(row)
   200  		if err != nil {
   201  			return nil, err
   202  		}
   203  	}
   204  	joinkvs, err := join.Table.Save()
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  	kvs = append(kvs, joinkvs...)
   209  	leftkvs, err := join.left.Save()
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  	kvs = append(kvs, leftkvs...)
   214  	rightkvs, err := join.right.Save()
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	kvs = append(kvs, rightkvs...)
   219  	return util.DelDupKey(kvs), nil
   220  }
   221  
   222  func (join *JoinTable) isLeftModify(row *Row) bool {
   223  	oldrow := &Row{Data: row.old}
   224  	for _, index := range join.leftIndex {
   225  		_, _, ismodify, err := join.left.getModify(row, oldrow, index)
   226  		if ismodify {
   227  			return true
   228  		}
   229  		if err != nil {
   230  			tablelog.Error("isLeftModify", "err", err)
   231  		}
   232  	}
   233  	return false
   234  }
   235  
   236  func (join *JoinTable) isRightModify(row *Row) bool {
   237  	oldrow := &Row{Data: row.old}
   238  	for _, index := range join.rightIndex {
   239  		_, _, ismodify, err := join.right.getModify(row, oldrow, index)
   240  		if ismodify {
   241  			return true
   242  		}
   243  		if err != nil {
   244  			tablelog.Error("isLeftModify", "err", err)
   245  		}
   246  	}
   247  	return false
   248  }
   249  
   250  func (join *JoinTable) saveLeft(row *Row) error {
   251  	if row.Ty == Update && !join.isLeftModify(row) {
   252  		return nil
   253  	}
   254  	olddata := &JoinData{}
   255  	rowjoin := join.meta.CreateRow()
   256  	rowjoin.Ty = row.Ty
   257  	rowjoin.Primary = row.Primary
   258  	rowjoin.Data.(*JoinData).Left = row.Data
   259  	olddata.Left = row.old
   260  	rightprimary, err := join.left.index(row, join.Fk)
   261  	if err != nil {
   262  		return err
   263  	}
   264  	rightrow, incache, err := join.right.findRow(rightprimary)
   265  	if err != nil {
   266  		return err
   267  	}
   268  	if incache && rightrow.Ty == Update {
   269  		olddata.Right = rightrow.old
   270  	} else {
   271  		olddata.Right = rightrow.Data
   272  	}
   273  	//只考虑 left 有变化, 那么就修改(如果right 也修改了,在right中处理)
   274  	if row.Ty == Update {
   275  		rowjoin.old = olddata
   276  	}
   277  	rowjoin.Data.(*JoinData).Right = rightrow.Data
   278  	join.addRowCache(rowjoin)
   279  	return nil
   280  }
   281  
   282  func (join *JoinTable) saveRight(row *Row) error {
   283  	if row.Ty == Update && !join.isRightModify(row) {
   284  		return nil
   285  	}
   286  	indexName := join.right.opt.Primary
   287  	indexValue := row.Primary
   288  	q := join.left.GetQuery(join.left.kvdb.(db.KVDB))
   289  	rows, err := q.ListIndex(indexName, indexValue, nil, 0, db.ListDESC)
   290  	if err != nil && err != types.ErrNotFound {
   291  		return err
   292  	}
   293  	rows, err = join.left.mergeCache(rows, indexName, indexValue)
   294  	if err != nil {
   295  		return err
   296  	}
   297  	for _, onerow := range rows {
   298  		olddata := &JoinData{Right: row.old, Left: onerow.Data}
   299  		if onerow.Ty == Update {
   300  			olddata.Left = onerow.old
   301  		}
   302  		rowjoin := join.meta.CreateRow()
   303  		rowjoin.Ty = row.Ty
   304  		rowjoin.Primary = onerow.Primary
   305  		if row.Ty == Update {
   306  			rowjoin.old = olddata
   307  		}
   308  		rowjoin.Data.(*JoinData).Right = row.Data
   309  		rowjoin.Data.(*JoinData).Left = onerow.Data
   310  		join.addRowCache(rowjoin)
   311  	}
   312  	return nil
   313  }
   314  
   315  //JoinData 由left 和 right 两个数据组成
   316  type JoinData struct {
   317  	Left  types.Message
   318  	Right types.Message
   319  }
   320  
   321  //Reset data
   322  func (msg *JoinData) Reset() {
   323  	msg.Left.Reset()
   324  	msg.Right.Reset()
   325  }
   326  
   327  //ProtoMessage data
   328  func (msg *JoinData) ProtoMessage() {
   329  	msg.Left.ProtoMessage()
   330  	msg.Right.ProtoMessage()
   331  }
   332  
   333  //String string
   334  func (msg *JoinData) String() string {
   335  	return msg.Left.String() + msg.Right.String()
   336  }
   337  
   338  //JoinMeta left right 合成的一个meta 结构
   339  type JoinMeta struct {
   340  	left  RowMeta
   341  	right RowMeta
   342  	data  *JoinData
   343  }
   344  
   345  //CreateRow create a meta struct
   346  func (tx *JoinMeta) CreateRow() *Row {
   347  	return &Row{Data: &JoinData{}}
   348  }
   349  
   350  //SetPayload 设置数据
   351  func (tx *JoinMeta) SetPayload(data types.Message) error {
   352  	if txdata, ok := data.(*JoinData); ok {
   353  		tx.data = txdata
   354  		if tx.data.Left != nil && tx.data.Right != nil {
   355  			err := tx.left.SetPayload(tx.data.Left)
   356  			if err != nil {
   357  				return err
   358  			}
   359  			err = tx.right.SetPayload(tx.data.Right)
   360  			if err != nil {
   361  				return err
   362  			}
   363  		}
   364  		return nil
   365  	}
   366  	return types.ErrTypeAsset
   367  }
   368  
   369  //Get 按照indexName 查询 indexValue
   370  func (tx *JoinMeta) Get(key string) ([]byte, error) {
   371  	indexs := strings.Split(key, joinsep)
   372  	//获取primary
   373  	if len(indexs) <= 1 {
   374  		return tx.left.Get(key)
   375  	}
   376  	var leftvalue []byte
   377  	var err error
   378  	if indexs[0] != "" {
   379  		leftvalue, err = tx.left.Get(indexs[0])
   380  		if err != nil {
   381  			return nil, err
   382  		}
   383  	}
   384  	rightvalue, err := tx.right.Get(indexs[1])
   385  	if err != nil {
   386  		return nil, err
   387  	}
   388  	return JoinKey(leftvalue, rightvalue), nil
   389  }
   390  
   391  //JoinKey 两个left 和 right key 合并成一个key
   392  func JoinKey(leftvalue, rightvalue []byte) []byte {
   393  	return types.Encode(&types.KeyValue{Key: leftvalue, Value: rightvalue})
   394  }