Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpTxn .Succeeded value is not set! #19678

Open
4 tasks done
purpleidea opened this issue Mar 27, 2025 · 0 comments
Open
4 tasks done

OpTxn .Succeeded value is not set! #19678

purpleidea opened this issue Mar 27, 2025 · 0 comments
Labels

Comments

@purpleidea
Copy link
Contributor

Bug report criteria

What happened?

Etcd has a .Succeeded field on a Txn response to know which branch of the transaction (then or else) was run. This is critically important to know what happened.

If you have an OpTxn then the child .Succeeded values are NOT SET and we seem to always see the false zero value.

A full code reproducer is included below.

What did you expect to happen?

At least one of the two branches should see a true. Neither does.

How can we reproduce it (as minimally and precisely as possible)?

Run etcd plainly in a terminal. Then run this code:
I left in my hacking mess for anyone curious. At least one of the "SUCCESS" lines should print true. They always print false.

// etcdbug

package main

import (
	"context"
	"fmt"

	pb "go.etcd.io/etcd/api/v3/etcdserverpb"
	clientv3 "go.etcd.io/etcd/client/v3"
)

func main() {

	client, err := clientv3.New(clientv3.Config{
		Endpoints: []string{"localhost:2379"},
	})
	if err != nil {
		panic(err)
	}
	defer client.Close()

	ops := []clientv3.Op{}
	{
		ifs := []clientv3.Cmp{}
		thn := []clientv3.Op{}
		els := []clientv3.Op{}

		path := "/foo"
		data := "hello"
		ifs = append(ifs, clientv3.Compare(clientv3.Value(path), "!=", data)) // THIS ONE IS !=
		els = append(els, clientv3.OpPut(path, data))

		op := clientv3.OpTxn(ifs, thn, els)
		ops = append(ops, op)
	}
	{
		ifs := []clientv3.Cmp{}
		thn := []clientv3.Op{}
		els := []clientv3.Op{}

		path := "/bar"
		data := "world"
		ifs = append(ifs, clientv3.Compare(clientv3.Value(path), "=", data)) // THIS ONE IS =
		els = append(els, clientv3.OpPut(path, data))

		op := clientv3.OpTxn(ifs, thn, els)
		ops = append(ops, op)
	}

	txn := client.Txn(context.Background())
	txnResp, err := txn.If().Then(ops...).Else().Commit()
	if err != nil {
		panic(err)
	}

	//
	// Who even knows the correct way to pull out nested data from the
	// protobuf mess? Various approaches have been tried, thoughts welcome.
	//

	realOut := txnResp.OpResponse().Txn()

	fmt.Printf("XXX: OUT(%T): %+v\n", realOut, realOut)
	if !realOut.Succeeded {
		// else branch happened
		panic("unexpected branch")
	}

	//responses := realOut.GetResponses() // doesn't work
	responses := realOut.Responses

	fmt.Printf("XXX: NUMBER OF RESPONSES: %+v\n", len(responses))

	for _, resp := range responses {
		fmt.Printf("XXX: RESP(%T): %+v\n", resp, resp)

		x := resp.GetResponse()
		fmt.Printf("X (%T) %+v\n", x, x)

		thing, ok := x.(*pb.ResponseOp_ResponseTxn)
		if !ok {
			panic("woops")
		}

		//x := pb.ResponseOp_ResponseTxn(resp)
		fmt.Printf("THING (%T) %+v\n", thing, thing)

		// eventually we should see `true` in one of the loop iterations
		fmt.Printf("SUCCESS1? %+v\n", thing.ResponseTxn.GetSucceeded())
		fmt.Printf("SUCCESS2? %+v\n", resp.GetResponseTxn().Succeeded)

		fmt.Printf("---------------------------------\n\n")
	}
}

Anything else we need to know?

No response

Etcd version (please run commands below)

$ etcd --version
# paste output here

$ etcdctl version
# paste output here

Etcd configuration (command line flags or environment variables)

paste your configuration here

Etcd debug information (please run commands below, feel free to obfuscate the IP address or FQDN in the output)

$ etcdctl member list -w table
# paste output here

$ etcdctl --endpoints=<member list> endpoint status -w table
# paste output here

Relevant log output

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

1 participant