-1

I am running into a problem mutating a flatbuffer from bytes. According to the flatbuffer documentation (https://github.com/google/flatbuffers/blob/master/docs/source/Tutorial.md), you can mutate fixed size fields, such as an int32. And as you can see below, the generated golang TestMutate has a MutateServerId() function. My problem is that after I mutate it, the bytes don't seem to have changed.

Here is my flatbuffer table definition:

namespace foo;

table TestMutate {
    serverId:int32;
}

Here is a unit test I wrote:

func TestMutateFlatbuffer2(test *testing.T) {
    builder := flatbuffers.NewBuilder(1024)
    packageWalletStorageServicesRPC.TestMutateStart(builder)
    packageWalletStorageServicesRPC.TestMutateAddServerId(builder, 1)
    endMessage := packageWalletStorageServicesRPC.TestMutateEnd(builder)
    builder.Finish(endMessage)

    bytes := builder.FinishedBytes()
    testMutate := packageWalletStorageServicesRPC.GetRootAsTestMutate(bytes, 0)
    success := testMutate.MutateServerId(2)
    if !success {
        panic("Server id not mutated.")
    } else {
        logger.Logf(logger.INFO, "serverId mutated to:%d", testMutate.ServerId())
    }

    mutatedBytes := testMutate.Table().Bytes
    if string(mutatedBytes) == string(bytes) {
        panic("Bytes were not mutated.")
    }
}

Here is the output from the test.

=== RUN   TestMutateFlatbuffer2
2019/08/01 19:33:56.801926 foo_test.go:389   : [ I ]: serverId mutated to:2
--- FAIL: TestMutateFlatbuffer2 (0.00s)
panic: Bytes were not mutated. [recovered]
    panic: Bytes were not mutated.

Notice that it appears I've mutated the underlying structure, but when I get the bytes of the flatbuffer, they're not changed. Question 1: Am I getting the bytes the correct way? Question 2: If I'm getting them in the right way, why are they not changed since the call to mutate seemed to succeed?

thebiggestlebowski
  • 2,610
  • 1
  • 33
  • 30

2 Answers2

1

Your test string(mutatedBytes) == string(bytes) fails because.. you are comparing the mutated buffer against itself. bytes refers to a buffer, that before your mutation contains a 1, and after it contains a 2. mutatedBytes points to the same buffer, and thus also contains a 2. The fact that testMutate.ServerId() returns 2 should tell you that the buffer got mutated succesfully, because there is no other way it could return 2 :) You'd have to make a (deep) copy of bytes before the mutation if you wanted this comparison to show that the buffers are different.

Aardappel
  • 5,559
  • 1
  • 19
  • 22
  • Thanks for the answer - your help is appreciated. I independently figured last night some hours after posting the testing bug where I'm comparing the same array to itself. There's two solutions, one of which is to copy the []byte as you suggest. The flatbuffer table definition I posted is a simplification of my real table. For me, the second and better solution is to have a nested flatbuffer table. So, table 1 has the bytes which don't mutate. Table 2 has the few bytes which I do mutate. This will be more efficient than copying an entire array. – thebiggestlebowski Aug 02 '19 at 20:08
0

There's at least two solutions to this problem. The second solution is better in my case because it results in less copying of bytes.

  1. By creating an intermediate string (and therefore, a copy of the bytes). Generally with flatbuffers you want to avoid copies, but for my use case, I'm ok with it.

  2. Wrap table definitions like this:


    table LotsOfData {
        notMutated:[ubyte];
    }

    table TestMutate {
        notMutated:LotsOfData;
        serverId:int32;
    }

thebiggestlebowski
  • 2,610
  • 1
  • 33
  • 30