github.com/tendermint/tmlibs@v0.9.0/db/remotedb/grpcdb/server.go (about) 1 package grpcdb 2 3 import ( 4 "context" 5 "net" 6 "sync" 7 "time" 8 9 "google.golang.org/grpc" 10 "google.golang.org/grpc/credentials" 11 12 "github.com/tendermint/tmlibs/db" 13 protodb "github.com/tendermint/tmlibs/db/remotedb/proto" 14 ) 15 16 // ListenAndServe is a blocking function that sets up a gRPC based 17 // server at the address supplied, with the gRPC options passed in. 18 // Normally in usage, invoke it in a goroutine like you would for http.ListenAndServe. 19 func ListenAndServe(addr, cert, key string, opts ...grpc.ServerOption) error { 20 ln, err := net.Listen("tcp", addr) 21 if err != nil { 22 return err 23 } 24 srv, err := NewServer(cert, key, opts...) 25 if err != nil { 26 return err 27 } 28 return srv.Serve(ln) 29 } 30 31 func NewServer(cert, key string, opts ...grpc.ServerOption) (*grpc.Server, error) { 32 creds, err := credentials.NewServerTLSFromFile(cert, key) 33 if err != nil { 34 return nil, err 35 } 36 opts = append(opts, grpc.Creds(creds)) 37 srv := grpc.NewServer(opts...) 38 protodb.RegisterDBServer(srv, new(server)) 39 return srv, nil 40 } 41 42 type server struct { 43 mu sync.Mutex 44 db db.DB 45 } 46 47 var _ protodb.DBServer = (*server)(nil) 48 49 // Init initializes the server's database. Only one type of database 50 // can be initialized per server. 51 // 52 // Dir is the directory on the file system in which the DB will be stored(if backed by disk) (TODO: remove) 53 // 54 // Name is representative filesystem entry's basepath 55 // 56 // Type can be either one of: 57 // * cleveldb (if built with gcc enabled) 58 // * fsdb 59 // * memdB 60 // * leveldb 61 // See https://godoc.org/github.com/tendermint/tmlibs/db#DBBackendType 62 func (s *server) Init(ctx context.Context, in *protodb.Init) (*protodb.Entity, error) { 63 s.mu.Lock() 64 defer s.mu.Unlock() 65 66 s.db = db.NewDB(in.Name, db.DBBackendType(in.Type), in.Dir) 67 return &protodb.Entity{CreatedAt: time.Now().Unix()}, nil 68 } 69 70 func (s *server) Delete(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) { 71 s.db.Delete(in.Key) 72 return nothing, nil 73 } 74 75 var nothing = new(protodb.Nothing) 76 77 func (s *server) DeleteSync(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) { 78 s.db.DeleteSync(in.Key) 79 return nothing, nil 80 } 81 82 func (s *server) Get(ctx context.Context, in *protodb.Entity) (*protodb.Entity, error) { 83 value := s.db.Get(in.Key) 84 return &protodb.Entity{Value: value}, nil 85 } 86 87 func (s *server) GetStream(ds protodb.DB_GetStreamServer) error { 88 // Receive routine 89 responsesChan := make(chan *protodb.Entity) 90 go func() { 91 defer close(responsesChan) 92 ctx := context.Background() 93 for { 94 in, err := ds.Recv() 95 if err != nil { 96 responsesChan <- &protodb.Entity{Err: err.Error()} 97 return 98 } 99 out, err := s.Get(ctx, in) 100 if err != nil { 101 if out == nil { 102 out = new(protodb.Entity) 103 out.Key = in.Key 104 } 105 out.Err = err.Error() 106 responsesChan <- out 107 return 108 } 109 110 // Otherwise continue on 111 responsesChan <- out 112 } 113 }() 114 115 // Send routine, block until we return 116 for out := range responsesChan { 117 if err := ds.Send(out); err != nil { 118 return err 119 } 120 } 121 return nil 122 } 123 124 func (s *server) Has(ctx context.Context, in *protodb.Entity) (*protodb.Entity, error) { 125 exists := s.db.Has(in.Key) 126 return &protodb.Entity{Exists: exists}, nil 127 } 128 129 func (s *server) Set(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) { 130 s.db.Set(in.Key, in.Value) 131 return nothing, nil 132 } 133 134 func (s *server) SetSync(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) { 135 s.db.SetSync(in.Key, in.Value) 136 return nothing, nil 137 } 138 139 func (s *server) Iterator(query *protodb.Entity, dis protodb.DB_IteratorServer) error { 140 it := s.db.Iterator(query.Start, query.End) 141 return s.handleIterator(it, dis.Send) 142 } 143 144 func (s *server) handleIterator(it db.Iterator, sendFunc func(*protodb.Iterator) error) error { 145 for it.Valid() { 146 start, end := it.Domain() 147 out := &protodb.Iterator{ 148 Domain: &protodb.Domain{Start: start, End: end}, 149 Valid: it.Valid(), 150 Key: it.Key(), 151 Value: it.Value(), 152 } 153 if err := sendFunc(out); err != nil { 154 return err 155 } 156 157 // Finally move the iterator forward 158 it.Next() 159 } 160 return nil 161 } 162 163 func (s *server) ReverseIterator(query *protodb.Entity, dis protodb.DB_ReverseIteratorServer) error { 164 it := s.db.ReverseIterator(query.Start, query.End) 165 return s.handleIterator(it, dis.Send) 166 } 167 168 func (s *server) Stats(context.Context, *protodb.Nothing) (*protodb.Stats, error) { 169 stats := s.db.Stats() 170 return &protodb.Stats{Data: stats, TimeAt: time.Now().Unix()}, nil 171 } 172 173 func (s *server) BatchWrite(c context.Context, b *protodb.Batch) (*protodb.Nothing, error) { 174 return s.batchWrite(c, b, false) 175 } 176 177 func (s *server) BatchWriteSync(c context.Context, b *protodb.Batch) (*protodb.Nothing, error) { 178 return s.batchWrite(c, b, true) 179 } 180 181 func (s *server) batchWrite(c context.Context, b *protodb.Batch, sync bool) (*protodb.Nothing, error) { 182 bat := s.db.NewBatch() 183 for _, op := range b.Ops { 184 switch op.Type { 185 case protodb.Operation_SET: 186 bat.Set(op.Entity.Key, op.Entity.Value) 187 case protodb.Operation_DELETE: 188 bat.Delete(op.Entity.Key) 189 } 190 } 191 if sync { 192 bat.WriteSync() 193 } else { 194 bat.Write() 195 } 196 return nothing, nil 197 }