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.

85 lines
1.8 KiB

  1. package themis
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "github.com/ngaut/log"
  6. "github.com/pingcap/go-hbase"
  7. )
  8. type ThemisScanner struct {
  9. scan *hbase.Scan
  10. txn *themisTxn
  11. tbl []byte
  12. }
  13. func newThemisScanner(tbl []byte, txn *themisTxn, batchSize int, c hbase.HBaseClient) *ThemisScanner {
  14. s := hbase.NewScan(tbl, batchSize, c)
  15. // add start ts
  16. b := bytes.NewBuffer(nil)
  17. binary.Write(b, binary.BigEndian, txn.startTs)
  18. s.AddAttr("_themisTransationStartTs_", b.Bytes())
  19. return &ThemisScanner{
  20. scan: s,
  21. txn: txn,
  22. tbl: tbl,
  23. }
  24. }
  25. func (s *ThemisScanner) setStartRow(start []byte) {
  26. s.scan.StartRow = start
  27. }
  28. func (s *ThemisScanner) setStopRow(stop []byte) {
  29. s.scan.StopRow = stop
  30. }
  31. func (s *ThemisScanner) SetTimeRange(tsRangeFrom uint64, tsRangeTo uint64) {
  32. s.scan.TsRangeFrom = tsRangeFrom
  33. s.scan.TsRangeTo = tsRangeTo
  34. }
  35. func (s *ThemisScanner) SetMaxVersions(maxVersions uint32) {
  36. s.scan.MaxVersions = maxVersions
  37. }
  38. func (s *ThemisScanner) createGetFromScan(row []byte) *hbase.Get {
  39. return s.scan.CreateGetFromScan(row)
  40. }
  41. func (s *ThemisScanner) Next() *hbase.ResultRow {
  42. r := s.scan.Next()
  43. if r == nil {
  44. return nil
  45. }
  46. // if we encounter conflict locks, we need to clean lock for this row and read again
  47. if isLockResult(r) {
  48. g := s.createGetFromScan(r.Row)
  49. r, err := s.txn.tryToCleanLockAndGetAgain(s.tbl, g, r.SortedColumns)
  50. if err != nil {
  51. log.Error(err)
  52. return nil
  53. }
  54. // empty result indicates the current row has been erased, we should get next row
  55. if r == nil {
  56. return s.Next()
  57. } else {
  58. return r
  59. }
  60. }
  61. return r
  62. }
  63. func (s *ThemisScanner) Closed() bool {
  64. return s.scan.Closed()
  65. }
  66. func (s *ThemisScanner) Close() {
  67. if !s.scan.Closed() {
  68. // TODO: handle error, now just log
  69. if err := s.scan.Close(); err != nil {
  70. log.Warnf("scanner close error, scan: %s, error: %v", s.scan, err)
  71. }
  72. }
  73. }