mirror of https://github.com/status-im/consul.git
Preserve ModifyIndex for unchanged entry in KVS TXN (#7832)
This commit is contained in:
parent
352ed2c13b
commit
6aecf89418
|
@ -127,13 +127,12 @@ func (s *Store) kvsSetTxn(tx *memdb.Txn, idx uint64, entry *structs.DirEntry, up
|
||||||
}
|
}
|
||||||
existing, _ := existingNode.(*structs.DirEntry)
|
existing, _ := existingNode.(*structs.DirEntry)
|
||||||
|
|
||||||
// Set the indexes.
|
// Set the CreateIndex.
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
entry.CreateIndex = existing.CreateIndex
|
entry.CreateIndex = existing.CreateIndex
|
||||||
} else {
|
} else {
|
||||||
entry.CreateIndex = idx
|
entry.CreateIndex = idx
|
||||||
}
|
}
|
||||||
entry.ModifyIndex = idx
|
|
||||||
|
|
||||||
// Preserve the existing session unless told otherwise. The "existing"
|
// Preserve the existing session unless told otherwise. The "existing"
|
||||||
// session for a new entry is "no session".
|
// session for a new entry is "no session".
|
||||||
|
@ -145,10 +144,15 @@ func (s *Store) kvsSetTxn(tx *memdb.Txn, idx uint64, entry *structs.DirEntry, up
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip write if the entry did not change
|
// Set the ModifyIndex.
|
||||||
if existing != nil && existing.Equal(entry) {
|
if existing != nil && existing.Equal(entry) {
|
||||||
|
// Skip further writing in the state store if the entry is not actually
|
||||||
|
// changed. Nevertheless, the input's ModifyIndex should be reset
|
||||||
|
// since the TXN API returns a copy in the response.
|
||||||
|
entry.ModifyIndex = existing.ModifyIndex
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
entry.ModifyIndex = idx
|
||||||
|
|
||||||
// Store the kv pair in the state store and update the index.
|
// Store the kv pair in the state store and update the index.
|
||||||
if err := s.insertKVTxn(tx, entry, false); err != nil {
|
if err := s.insertKVTxn(tx, entry, false); err != nil {
|
||||||
|
|
|
@ -1252,3 +1252,132 @@ func TestStateStore_Txn_KVS_RO_Safety(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStateStore_Txn_KVS_ModifyIndexes(t *testing.T) {
|
||||||
|
s := testStateStore(t)
|
||||||
|
|
||||||
|
// Create KV entries in the state store.
|
||||||
|
testSetKey(t, s, 1, "foo/a", "bar", nil)
|
||||||
|
testSetKey(t, s, 2, "foo/b", "bar", nil)
|
||||||
|
|
||||||
|
// Set up a transaction that actually changes `a`,
|
||||||
|
// but passes original value for `b`.
|
||||||
|
ops := structs.TxnOps{
|
||||||
|
&structs.TxnOp{
|
||||||
|
KV: &structs.TxnKVOp{
|
||||||
|
Verb: api.KVCAS,
|
||||||
|
DirEnt: structs.DirEntry{
|
||||||
|
Key: "foo/a",
|
||||||
|
Value: []byte("new"),
|
||||||
|
RaftIndex: structs.RaftIndex{
|
||||||
|
ModifyIndex: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&structs.TxnOp{
|
||||||
|
KV: &structs.TxnKVOp{
|
||||||
|
Verb: api.KVCAS,
|
||||||
|
DirEnt: structs.DirEntry{
|
||||||
|
Key: "foo/b",
|
||||||
|
Value: []byte("bar"),
|
||||||
|
RaftIndex: structs.RaftIndex{
|
||||||
|
ModifyIndex: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
results, errors := s.TxnRW(3, ops)
|
||||||
|
if len(errors) > 0 {
|
||||||
|
t.Fatalf("err: %v", errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the response looks as expected.
|
||||||
|
expected := structs.TxnResults{
|
||||||
|
&structs.TxnResult{
|
||||||
|
KV: &structs.DirEntry{
|
||||||
|
Key: "foo/a",
|
||||||
|
RaftIndex: structs.RaftIndex{
|
||||||
|
CreateIndex: 1,
|
||||||
|
ModifyIndex: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&structs.TxnResult{
|
||||||
|
KV: &structs.DirEntry{
|
||||||
|
Key: "foo/b",
|
||||||
|
RaftIndex: structs.RaftIndex{
|
||||||
|
CreateIndex: 2,
|
||||||
|
ModifyIndex: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if len(results) != len(expected) {
|
||||||
|
t.Fatalf("bad: %v", results)
|
||||||
|
}
|
||||||
|
for i, e := range expected {
|
||||||
|
if e.KV.Key != results[i].KV.Key {
|
||||||
|
t.Fatalf("expected key %s, got %s", e.KV.Key, results[i].KV.Key)
|
||||||
|
}
|
||||||
|
if e.KV.LockIndex != results[i].KV.LockIndex {
|
||||||
|
t.Fatalf("expected lock index %d, got %d", e.KV.LockIndex, results[i].KV.LockIndex)
|
||||||
|
}
|
||||||
|
if e.KV.CreateIndex != results[i].KV.CreateIndex {
|
||||||
|
t.Fatalf("expected create index %d, got %d", e.KV.CreateIndex, results[i].KV.CreateIndex)
|
||||||
|
}
|
||||||
|
if e.KV.ModifyIndex != results[i].KV.ModifyIndex {
|
||||||
|
t.Fatalf("expected modify index %d, got %d", e.KV.ModifyIndex, results[i].KV.ModifyIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull the resulting state store contents.
|
||||||
|
idx, actual, err := s.KVSList(nil, "", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
if idx != 3 {
|
||||||
|
t.Fatalf("bad index: %d", idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure it looks as expected.
|
||||||
|
entries := structs.DirEntries{
|
||||||
|
&structs.DirEntry{
|
||||||
|
Key: "foo/a",
|
||||||
|
Value: []byte("new"),
|
||||||
|
RaftIndex: structs.RaftIndex{
|
||||||
|
CreateIndex: 1,
|
||||||
|
ModifyIndex: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&structs.DirEntry{
|
||||||
|
Key: "foo/b",
|
||||||
|
Value: []byte("bar"),
|
||||||
|
RaftIndex: structs.RaftIndex{
|
||||||
|
CreateIndex: 2,
|
||||||
|
ModifyIndex: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if len(actual) != len(entries) {
|
||||||
|
t.Fatalf("bad len: %d != %d", len(actual), len(entries))
|
||||||
|
}
|
||||||
|
for i, e := range entries {
|
||||||
|
if e.Key != actual[i].Key {
|
||||||
|
t.Fatalf("expected key %s, got %s", e.Key, actual[i].Key)
|
||||||
|
}
|
||||||
|
if string(e.Value) != string(actual[i].Value) {
|
||||||
|
t.Fatalf("expected value %s, got %s", e.Value, actual[i].Value)
|
||||||
|
}
|
||||||
|
if e.LockIndex != actual[i].LockIndex {
|
||||||
|
t.Fatalf("expected lock index %d, got %d", e.LockIndex, actual[i].LockIndex)
|
||||||
|
}
|
||||||
|
if e.CreateIndex != actual[i].CreateIndex {
|
||||||
|
t.Fatalf("expected create index %d, got %d", e.CreateIndex, actual[i].CreateIndex)
|
||||||
|
}
|
||||||
|
if e.ModifyIndex != actual[i].ModifyIndex {
|
||||||
|
t.Fatalf("expected modify index %d, got %d", e.ModifyIndex, actual[i].ModifyIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue