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.

162 lines
4.1 KiB

  1. package grpcdb
  2. import (
  3. "context"
  4. "net"
  5. "sync"
  6. "time"
  7. "google.golang.org/grpc"
  8. "github.com/tendermint/tmlibs/db"
  9. protodb "github.com/tendermint/tmlibs/proto"
  10. )
  11. // ListenAndServe is a blocking function that sets up a gRPC based
  12. // server at the address supplied, with the gRPC options passed in.
  13. // Normally in usage, invoke it in a goroutine like you would for http.ListenAndServe.
  14. func ListenAndServe(addr string, opts ...grpc.ServerOption) error {
  15. ln, err := net.Listen("tcp", addr)
  16. if err != nil {
  17. return err
  18. }
  19. srv := NewServer(opts...)
  20. return srv.Serve(ln)
  21. }
  22. func NewServer(opts ...grpc.ServerOption) *grpc.Server {
  23. srv := grpc.NewServer(opts...)
  24. protodb.RegisterDBServer(srv, new(server))
  25. return srv
  26. }
  27. type server struct {
  28. mu sync.Mutex
  29. db db.DB
  30. }
  31. var _ protodb.DBServer = (*server)(nil)
  32. // Init initializes the server's database. Only one type of database
  33. // can be initialized per server.
  34. //
  35. // Dir is the directory on the file system in which the DB will be stored(if backed by disk) (TODO: remove)
  36. //
  37. // Name is representative filesystem entry's basepath
  38. //
  39. // Type can be either one of:
  40. // * cleveldb (if built with gcc enabled)
  41. // * fsdb
  42. // * memdB
  43. // * leveldb
  44. // See https://godoc.org/github.com/tendermint/tmlibs/db#DBBackendType
  45. func (s *server) Init(ctx context.Context, in *protodb.Init) (*protodb.Entity, error) {
  46. s.mu.Lock()
  47. defer s.mu.Unlock()
  48. s.db = db.NewDB(in.Name, db.DBBackendType(in.Type), in.Dir)
  49. return &protodb.Entity{TimeAt: time.Now().Unix()}, nil
  50. }
  51. func (s *server) Delete(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) {
  52. s.db.Delete(in.Key)
  53. return nothing, nil
  54. }
  55. var nothing = new(protodb.Nothing)
  56. func (s *server) DeleteSync(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) {
  57. s.db.DeleteSync(in.Key)
  58. return nothing, nil
  59. }
  60. func (s *server) Get(ctx context.Context, in *protodb.Entity) (*protodb.Entity, error) {
  61. value := s.db.Get(in.Key)
  62. return &protodb.Entity{Value: value}, nil
  63. }
  64. func (s *server) GetStream(ds protodb.DB_GetStreamServer) error {
  65. // Receive routine
  66. responsesChan := make(chan *protodb.Entity)
  67. go func() {
  68. defer close(responsesChan)
  69. ctx := context.Background()
  70. for {
  71. in, err := ds.Recv()
  72. if err != nil {
  73. responsesChan <- &protodb.Entity{Err: err.Error()}
  74. return
  75. }
  76. out, err := s.Get(ctx, in)
  77. if err != nil {
  78. if out == nil {
  79. out = new(protodb.Entity)
  80. out.Key = in.Key
  81. }
  82. out.Err = err.Error()
  83. responsesChan <- out
  84. return
  85. }
  86. // Otherwise continue on
  87. responsesChan <- out
  88. }
  89. }()
  90. // Send routine, block until we return
  91. for out := range responsesChan {
  92. if err := ds.Send(out); err != nil {
  93. return err
  94. }
  95. }
  96. return nil
  97. }
  98. func (s *server) Has(ctx context.Context, in *protodb.Entity) (*protodb.Entity, error) {
  99. exists := s.db.Has(in.Key)
  100. return &protodb.Entity{Exists: exists}, nil
  101. }
  102. func (s *server) Set(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) {
  103. s.db.Set(in.Key, in.Value)
  104. return nothing, nil
  105. }
  106. func (s *server) SetSync(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) {
  107. s.db.SetSync(in.Key, in.Value)
  108. return nothing, nil
  109. }
  110. func (s *server) Iterator(query *protodb.Entity, dis protodb.DB_IteratorServer) error {
  111. it := s.db.Iterator(query.Start, query.End)
  112. return s.handleIterator(it, dis.Send)
  113. }
  114. func (s *server) handleIterator(it db.Iterator, sendFunc func(*protodb.Iterator) error) error {
  115. for it.Valid() {
  116. start, end := it.Domain()
  117. out := &protodb.Iterator{
  118. Domain: &protodb.DDomain{Start: start, End: end},
  119. Valid: it.Valid(),
  120. Key: it.Key(),
  121. Value: it.Value(),
  122. }
  123. if err := sendFunc(out); err != nil {
  124. return err
  125. }
  126. // Finally move the iterator forward
  127. it.Next()
  128. }
  129. return nil
  130. }
  131. func (s *server) ReverseIterator(query *protodb.Entity, dis protodb.DB_ReverseIteratorServer) error {
  132. it := s.db.ReverseIterator(query.Start, query.End)
  133. return s.handleIterator(it, dis.Send)
  134. }
  135. func (s *server) Stats(context.Context, *protodb.Nothing) (*protodb.Stats, error) {
  136. stats := s.db.Stats()
  137. return &protodb.Stats{Data: stats, TimeAt: time.Now().Unix()}, nil
  138. }