func doDeleteRange(kv dstorage.KV, dr *pb.DeleteRangeRequest) *pb.DeleteRangeResponse { resp := &pb.DeleteRangeResponse{} resp.Header = &pb.ResponseHeader{} _, rev := kv.DeleteRange(dr.Key, dr.RangeEnd) resp.Header.Index = rev return resp }
func applyPut(kv dstorage.KV, p *pb.PutRequest) (*pb.PutResponse, error) { resp := &pb.PutResponse{} resp.Header = &pb.ResponseHeader{} rev := kv.Put(p.Key, p.Value) resp.Header.Revision = rev return resp, nil }
func doPut(kv dstorage.KV, p *pb.PutRequest) *pb.PutResponse { resp := &pb.PutResponse{} resp.Header = &pb.ResponseHeader{} rev := kv.Put(p.Key, p.Value) resp.Header.Index = rev return resp }
func applyRange(txnID int64, kv dstorage.KV, r *pb.RangeRequest) (*pb.RangeResponse, error) { resp := &pb.RangeResponse{} resp.Header = &pb.ResponseHeader{} var ( kvs []storagepb.KeyValue rev int64 err error ) if txnID != noTxn { kvs, rev, err = kv.TxnRange(txnID, r.Key, r.RangeEnd, r.Limit, 0) if err != nil { return nil, err } } else { kvs, rev, err = kv.Range(r.Key, r.RangeEnd, r.Limit, 0) if err != nil { return nil, err } } resp.Header.Revision = rev for i := range kvs { resp.Kvs = append(resp.Kvs, &kvs[i]) } return resp, nil }
func applyDeleteRange(kv dstorage.KV, dr *pb.DeleteRangeRequest) (*pb.DeleteRangeResponse, error) { resp := &pb.DeleteRangeResponse{} resp.Header = &pb.ResponseHeader{} _, rev := kv.DeleteRange(dr.Key, dr.RangeEnd) resp.Header.Revision = rev return resp, nil }
func applyDeleteRange(txnID int64, kv dstorage.KV, dr *pb.DeleteRangeRequest) (*pb.DeleteRangeResponse, error) { resp := &pb.DeleteRangeResponse{} resp.Header = &pb.ResponseHeader{} var ( n int64 rev int64 err error ) if isGteRange(dr.RangeEnd) { dr.RangeEnd = []byte{} } if txnID != noTxn { n, rev, err = kv.TxnDeleteRange(txnID, dr.Key, dr.RangeEnd) if err != nil { return nil, err } } else { n, rev = kv.DeleteRange(dr.Key, dr.RangeEnd) } resp.Deleted = n resp.Header.Revision = rev return resp, nil }
func applyRange(txnID int64, kv dstorage.KV, r *pb.RangeRequest) (*pb.RangeResponse, error) { resp := &pb.RangeResponse{} resp.Header = &pb.ResponseHeader{} var ( kvs []storagepb.KeyValue rev int64 err error ) limit := r.Limit if r.SortOrder != pb.RangeRequest_NONE { // fetch everything; sort and truncate afterwards limit = 0 } if txnID != noTxn { kvs, rev, err = kv.TxnRange(txnID, r.Key, r.RangeEnd, limit, 0) if err != nil { return nil, err } } else { kvs, rev, err = kv.Range(r.Key, r.RangeEnd, limit, 0) if err != nil { return nil, err } } if r.SortOrder != pb.RangeRequest_NONE { var sorter sort.Interface switch { case r.SortTarget == pb.RangeRequest_KEY: sorter = &kvSortByKey{&kvSort{kvs}} case r.SortTarget == pb.RangeRequest_VERSION: sorter = &kvSortByVersion{&kvSort{kvs}} case r.SortTarget == pb.RangeRequest_CREATE: sorter = &kvSortByCreate{&kvSort{kvs}} case r.SortTarget == pb.RangeRequest_MOD: sorter = &kvSortByMod{&kvSort{kvs}} case r.SortTarget == pb.RangeRequest_VALUE: sorter = &kvSortByValue{&kvSort{kvs}} } switch { case r.SortOrder == pb.RangeRequest_ASCEND: sort.Sort(sorter) case r.SortOrder == pb.RangeRequest_DESCEND: sort.Sort(sort.Reverse(sorter)) } if r.Limit > 0 && len(kvs) > int(r.Limit) { kvs = kvs[:r.Limit] } } resp.Header.Revision = rev for i := range kvs { resp.Kvs = append(resp.Kvs, &kvs[i]) } return resp, nil }
// applyCompare applies the compare request. // applyCompare should only be called within a txn request and an valid txn ID must // be presented. Or applyCompare panics. // It returns the revision at which the comparison happens. If the comparison // succeeds, the it returns true. Otherwise it returns false. func applyCompare(txnID int64, kv dstorage.KV, c *pb.Compare) (int64, bool) { if txnID == noTxn { panic("applyCompare called with noTxn") } ckvs, rev, err := kv.TxnRange(txnID, c.Key, nil, 1, 0) if err != nil { if err == dstorage.ErrTxnIDMismatch { panic("unexpected txn ID mismatch error") } return rev, false } var ckv storagepb.KeyValue if len(ckvs) != 0 { ckv = ckvs[0] } else { // Use the zero value of ckv normally. However... if c.Target == pb.Compare_VALUE { // Always fail if we're comparing a value on a key that doesn't exist. // We can treat non-existence as the empty set explicitly, such that // even a key with a value of length 0 bytes is still a real key // that was written that way return rev, false } } // -1 is less, 0 is equal, 1 is greater var result int switch c.Target { case pb.Compare_VALUE: result = bytes.Compare(ckv.Value, c.Value) case pb.Compare_CREATE: result = compareInt64(ckv.CreateRevision, c.CreateRevision) case pb.Compare_MOD: result = compareInt64(ckv.ModRevision, c.ModRevision) case pb.Compare_VERSION: result = compareInt64(ckv.Version, c.Version) } switch c.Result { case pb.Compare_EQUAL: if result != 0 { return rev, false } case pb.Compare_GREATER: if result != 1 { return rev, false } case pb.Compare_LESS: if result != -1 { return rev, false } } return rev, true }
func applyCompaction(kv dstorage.KV, compaction *pb.CompactionRequest) (*pb.CompactionResponse, error) { resp := &pb.CompactionResponse{} resp.Header = &pb.ResponseHeader{} err := kv.Compact(compaction.Revision) if err != nil { return nil, err } // get the current revision. which key to get is not important. _, resp.Header.Revision, _ = kv.Range([]byte("compaction"), nil, 1, 0) return resp, err }
func doCompare(kv dstorage.KV, c *pb.Compare) (int64, bool) { ckvs, rev, err := kv.Range(c.Key, nil, 1, 0) if err != nil { return rev, false } var ckv storagepb.KeyValue if len(ckvs) != 0 { ckv = ckvs[0] } // -1 is less, 0 is equal, 1 is greater var result int switch c.Target { case pb.Compare_VALUE: tv, _ := c.TargetUnion.(*pb.Compare_Value) if tv != nil { result = bytes.Compare(ckv.Value, tv.Value) } case pb.Compare_CREATE: tv, _ := c.TargetUnion.(*pb.Compare_CreateRevision) if tv != nil { result = compareInt64(ckv.CreateRevision, tv.CreateRevision) } case pb.Compare_MOD: tv, _ := c.TargetUnion.(*pb.Compare_ModRevision) if tv != nil { result = compareInt64(ckv.ModRevision, tv.ModRevision) } case pb.Compare_VERSION: tv, _ := c.TargetUnion.(*pb.Compare_Version) if tv != nil { result = compareInt64(ckv.Version, tv.Version) } } switch c.Result { case pb.Compare_EQUAL: if result != 0 { return rev, false } case pb.Compare_GREATER: if result != 1 { return rev, false } case pb.Compare_LESS: if result != -1 { return rev, false } } return rev, true }
func doRange(kv dstorage.KV, r *pb.RangeRequest) *pb.RangeResponse { resp := &pb.RangeResponse{} resp.Header = &pb.ResponseHeader{} kvs, rev, err := kv.Range(r.Key, r.RangeEnd, r.Limit, 0) if err != nil { panic("not handled error") } resp.Header.Index = rev for i := range kvs { resp.Kvs = append(resp.Kvs, &kvs[i]) } return resp }
func applyTxn(kv dstorage.KV, le lease.Lessor, rt *pb.TxnRequest) (*pb.TxnResponse, error) { var revision int64 ok := true for _, c := range rt.Compare { if revision, ok = applyCompare(kv, c); !ok { break } } var reqs []*pb.RequestUnion if ok { reqs = rt.Success } else { reqs = rt.Failure } if err := checkRequestLeases(le, reqs); err != nil { return nil, err } if err := checkRequestRange(kv, reqs); err != nil { return nil, err } // When executing the operations of txn, we need to hold the txn lock. // So the reader will not see any intermediate results. txnID := kv.TxnBegin() defer func() { err := kv.TxnEnd(txnID) if err != nil { panic(fmt.Sprint("unexpected error when closing txn", txnID)) } }() resps := make([]*pb.ResponseUnion, len(reqs)) for i := range reqs { resps[i] = applyUnion(txnID, kv, reqs[i]) } if len(resps) != 0 { revision += 1 } txnResp := &pb.TxnResponse{} txnResp.Header = &pb.ResponseHeader{} txnResp.Header.Revision = revision txnResp.Responses = resps txnResp.Succeeded = ok return txnResp, nil }
func applyRange(kv dstorage.KV, r *pb.RangeRequest) (*pb.RangeResponse, error) { resp := &pb.RangeResponse{} resp.Header = &pb.ResponseHeader{} kvs, rev, err := kv.Range(r.Key, r.RangeEnd, r.Limit, 0) if err != nil { return nil, err } resp.Header.Revision = rev for i := range kvs { resp.Kvs = append(resp.Kvs, &kvs[i]) } return resp, nil }
func checkRequestRange(kv dstorage.KV, reqs []*pb.RequestUnion) error { for _, requ := range reqs { greq := requ.RequestRange if greq == nil || greq.Revision == 0 { continue } if greq.Revision > kv.Rev() { return dstorage.ErrFutureRev } if greq.Revision < kv.FirstRev() { return dstorage.ErrCompacted } } return nil }
func applyTxn(kv dstorage.KV, le lease.Lessor, rt *pb.TxnRequest) (*pb.TxnResponse, error) { var revision int64 txnID := kv.TxnBegin() defer func() { err := kv.TxnEnd(txnID) if err != nil { panic(fmt.Sprint("unexpected error when closing txn", txnID)) } }() ok := true for _, c := range rt.Compare { if revision, ok = applyCompare(txnID, kv, c); !ok { break } } // TODO: check potential errors before actually applying anything var reqs []*pb.RequestUnion if ok { reqs = rt.Success } else { reqs = rt.Failure } if err := checkRequestLeases(le, reqs); err != nil { return nil, err } resps := make([]*pb.ResponseUnion, len(reqs)) for i := range reqs { resps[i] = applyUnion(txnID, kv, reqs[i]) } if len(resps) != 0 { revision += 1 } txnResp := &pb.TxnResponse{} txnResp.Header = &pb.ResponseHeader{} txnResp.Header.Revision = revision txnResp.Responses = resps txnResp.Succeeded = ok return txnResp, nil }
func applyPut(txnID int64, kv dstorage.KV, p *pb.PutRequest) (*pb.PutResponse, error) { resp := &pb.PutResponse{} resp.Header = &pb.ResponseHeader{} var ( rev int64 err error ) if txnID != noTxn { rev, err = kv.TxnPut(txnID, p.Key, p.Value, lease.LeaseID(p.Lease)) if err != nil { return nil, err } } else { rev = kv.Put(p.Key, p.Value, lease.LeaseID(p.Lease)) } resp.Header.Revision = rev return resp, nil }
// applyCompare applies the compare request. // applyCompare should only be called within a txn request and an valid txn ID must // be presented. Or applyCompare panics. // It returns the revision at which the comparison happens. If the comparison // succeeds, the it returns true. Otherwise it returns false. func applyCompare(txnID int64, kv dstorage.KV, c *pb.Compare) (int64, bool) { if txnID == noTxn { panic("applyCompare called with noTxn") } ckvs, rev, err := kv.TxnRange(txnID, c.Key, nil, 1, 0) if err != nil { if err == dstorage.ErrTxnIDMismatch { panic("unexpected txn ID mismatch error") } return rev, false } ckv := ckvs[0] // -1 is less, 0 is equal, 1 is greater var result int switch c.Target { case pb.Compare_VALUE: result = bytes.Compare(ckv.Value, c.Value) case pb.Compare_CREATE: result = compareInt64(ckv.CreateRevision, c.CreateRevision) case pb.Compare_MOD: result = compareInt64(ckv.ModRevision, c.ModRevision) case pb.Compare_VERSION: result = compareInt64(ckv.Version, c.Version) } switch c.Result { case pb.Compare_EQUAL: if result != 0 { return rev, false } case pb.Compare_GREATER: if result != 1 { return rev, false } case pb.Compare_LESS: if result != -1 { return rev, false } } return rev, true }
func applyCompare(kv dstorage.KV, c *pb.Compare) (int64, bool) { ckvs, rev, err := kv.Range(c.Key, nil, 1, 0) if err != nil { return rev, false } ckv := ckvs[0] // -1 is less, 0 is equal, 1 is greater var result int switch c.Target { case pb.Compare_VALUE: result = bytes.Compare(ckv.Value, c.Value) case pb.Compare_CREATE: result = compareInt64(ckv.CreateRevision, c.CreateRevision) case pb.Compare_MOD: result = compareInt64(ckv.ModRevision, c.ModRevision) case pb.Compare_VERSION: result = compareInt64(ckv.Version, c.Version) } switch c.Result { case pb.Compare_EQUAL: if result != 0 { return rev, false } case pb.Compare_GREATER: if result != 1 { return rev, false } case pb.Compare_LESS: if result != -1 { return rev, false } } return rev, true }
func applyPut(txnID int64, kv dstorage.KV, le lease.Lessor, p *pb.PutRequest) (*pb.PutResponse, error) { resp := &pb.PutResponse{} resp.Header = &pb.ResponseHeader{} var ( rev int64 err error ) if txnID != noTxn { rev, err = kv.TxnPut(txnID, p.Key, p.Value, lease.LeaseID(p.Lease)) if err != nil { return nil, err } } else { leaseID := lease.LeaseID(p.Lease) if leaseID != lease.NoLease { if l := le.Lookup(leaseID); l == nil { return nil, lease.ErrLeaseNotFound } } rev = kv.Put(p.Key, p.Value, leaseID) } resp.Header.Revision = rev return resp, nil }
func applyRange(txnID int64, kv dstorage.KV, r *pb.RangeRequest) (*pb.RangeResponse, error) { resp := &pb.RangeResponse{} resp.Header = &pb.ResponseHeader{} var ( kvs []storagepb.KeyValue rev int64 err error ) // grpc sends empty byte strings as nils, so use a '\0' to indicate // wanting a >= query if len(r.RangeEnd) == 1 && r.RangeEnd[0] == 0 { r.RangeEnd = []byte{} } limit := r.Limit if r.SortOrder != pb.RangeRequest_NONE { // fetch everything; sort and truncate afterwards limit = 0 } if limit > 0 { // fetch one extra for 'more' flag limit = limit + 1 } if txnID != noTxn { kvs, rev, err = kv.TxnRange(txnID, r.Key, r.RangeEnd, limit, r.Revision) if err != nil { return nil, err } } else { kvs, rev, err = kv.Range(r.Key, r.RangeEnd, limit, r.Revision) if err != nil { return nil, err } } if r.SortOrder != pb.RangeRequest_NONE { var sorter sort.Interface switch { case r.SortTarget == pb.RangeRequest_KEY: sorter = &kvSortByKey{&kvSort{kvs}} case r.SortTarget == pb.RangeRequest_VERSION: sorter = &kvSortByVersion{&kvSort{kvs}} case r.SortTarget == pb.RangeRequest_CREATE: sorter = &kvSortByCreate{&kvSort{kvs}} case r.SortTarget == pb.RangeRequest_MOD: sorter = &kvSortByMod{&kvSort{kvs}} case r.SortTarget == pb.RangeRequest_VALUE: sorter = &kvSortByValue{&kvSort{kvs}} } switch { case r.SortOrder == pb.RangeRequest_ASCEND: sort.Sort(sorter) case r.SortOrder == pb.RangeRequest_DESCEND: sort.Sort(sort.Reverse(sorter)) } } if r.Limit > 0 && len(kvs) > int(r.Limit) { kvs = kvs[:r.Limit] resp.More = true } resp.Header.Revision = rev for i := range kvs { resp.Kvs = append(resp.Kvs, &kvs[i]) } return resp, nil }