Nodes aren't ordered correctly if the query+mutate are in the same txn

Moved from GitHub dgraph/5937

Posted by jostillmanns:

What version of Dgraph are you using?

v20.03.1

Have you tried reproducing the issue with the latest release?

no

Steps to reproduce the issue (command/config used to run Dgraph).

run this test:

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"testing"

	"github.com/dgraph-io/dgo/v2"
	"github.com/dgraph-io/dgo/v2/protos/api"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc"
)

func Test_it_orders_correctly_after_update(t *testing.T) {
	conn, err := grpc.Dial(dgraphAddr(), grpc.WithInsecure())
	if err != nil {
		t.Fatalf("conntect: %v", err)
	}

	dg := dgo.NewDgraphClient(api.NewDgraphClient(conn))
	defer dg.Alter(context.Background(), &api.Operation{DropAll: true})

	schema := `
type node {
  node.order: int
  node.children: [uid]
}

node.order: int .
node.children: [uid] .
`
	err = dg.Alter(context.Background(), &api.Operation{Schema: schema})
	require.NoError(t, err)

	type Node struct {
		ID   string `json:"uid"`
		Type string `json:"dgraph.type"`

		Order    int    `json:"node.order"`
		Children []Node `json:"node.children"`
	}

	in := Node{
		ID:   "_:probe",
		Type: "node",
		Children: []Node{
			{
				Type:  "node",
				Order: 1,
			},
			{
				Type:  "node",
				Order: 2,
			},
			{
				Type:  "node",
				Order: 3,
			},
		},
	}

	js, err := json.Marshal(in)
	require.NoError(t, err)

	mutateResp, err := dg.NewTxn().Mutate(context.Background(), &api.Mutation{SetJson: js, CommitNow: true})
	require.NoError(t, err)

	q := `
query {
  nodes (func: uid(%s)) {
    uid
    node.children (orderasc: node.order) {
      uid
      node.order
    }
  }
}
`
	resp, err := dg.NewTxn().Query(context.Background(), fmt.Sprintf(q, mutateResp.Uids["probe"]))
	require.NoError(t, err)

	var res struct {
		Nodes []Node `json:"nodes"`
	}
	err = json.Unmarshal(resp.GetJson(), &res)
	require.NoError(t, err)

	txn := dg.NewTxn()

	delete, err := json.Marshal(map[string]interface{}{"uid": res.Nodes[0].ID, "node.childen": nil})
	require.NoError(t, err)

	_, err = txn.Mutate(context.Background(), &api.Mutation{DeleteJson: delete})
	require.NoError(t, err)

	update, err := json.Marshal(Node{
		ID: res.Nodes[0].ID,
		Children: []Node{
			{ID: res.Nodes[0].Children[2].ID, Order: 1},
			{ID: res.Nodes[0].Children[1].ID, Order: 2},
			{ID: res.Nodes[0].Children[0].ID, Order: 3},
		},
	})
	require.NoError(t, err)

	_, err = txn.Mutate(context.Background(), &api.Mutation{SetJson: update})

	resp, err = txn.Query(context.Background(), fmt.Sprintf(q, res.Nodes[0].ID))
	require.NoError(t, err)

	err = txn.Commit(context.Background())
	require.NoError(t, err)

	var postUpdate struct {
		Nodes []Node `json:"nodes"`
	}
	err = json.Unmarshal(resp.GetJson(), &postUpdate)
	require.NoError(t, err)

	require.Equal(t, 1, postUpdate.Nodes[0].Children[0].Order) // <- THIS FAILS
}

Expected behaviour and actual result.

the nodes referenced by node.children should be sorted correctly post .Mutate(), however the query yields nodes in incorrect order. I suspect this is because of the query being in the same txn as the .Mutate() statements, as the query shows a correct order outside of the txn.

3 Likes

any chance someone could take a look at this?

Hi @Joschka, I am looking into this and will get back soon.

Hi @Joschka,

I agree that this looks like a bug. When I read the same query again in a new transaction, the order is as expected and the test passes (just as you have already noted). I am reviewing this with the team and will update this post.

Thanks for your patience.

Regards,
Anand.

2 Likes

Hi @Joschka, just to confirm: we have opened a JIRA ticket for this and will be looking into this. Will keep you posted. Cheers!

1 Like