Skip to content

Commit 005ea6e

Browse files
martinmrdna2github
authored andcommitted
Backup schema keys in incremental backups. (dgraph-io#5147)
The full schema should be backed up during incremental backups. During restore, the schema should be cleared before processing each backup to end up with only the final schema.
1 parent eecf661 commit 005ea6e

7 files changed

Lines changed: 111 additions & 49 deletions

File tree

systest/backup/encryption/backup_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,12 @@ func runRestore(t *testing.T, lastDir string, commitTs uint64) map[string]string
289289
restored, err := testutil.GetPredicateValues(pdir, "movie", commitTs)
290290
require.NoError(t, err)
291291

292-
restoredPreds, err := testutil.GetPredicateNames(pdir, commitTs)
292+
restoredPreds, err := testutil.GetPredicateNames(pdir)
293293
require.NoError(t, err)
294294
require.ElementsMatch(t, []string{"dgraph.graphql.schema", "dgraph.graphql.xid",
295295
"dgraph.type", "movie"}, restoredPreds)
296296

297-
restoredTypes, err := testutil.GetTypeNames(pdir, commitTs)
297+
restoredTypes, err := testutil.GetTypeNames(pdir)
298298
require.NoError(t, err)
299299
require.ElementsMatch(t, []string{"Node", "dgraph.graphql"}, restoredTypes)
300300

systest/backup/filesystem/backup_test.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ func TestBackupFilesystem(t *testing.T) {
106106
_ = runBackup(t, 3, 1)
107107
restored := runRestore(t, copyBackupDir, "", math.MaxUint64)
108108

109+
// Check the predicates and types in the schema are as expected.
110+
// TODO: refactor tests so that minio and filesystem tests share most of their logic.
111+
preds := []string{"dgraph.graphql.schema", "dgraph.graphql.xid", "dgraph.type", "movie"}
112+
types := []string{"Node", "dgraph.graphql"}
113+
testutil.CheckSchema(t, preds, types)
114+
109115
checks := []struct {
110116
blank, expected string
111117
}{
@@ -130,10 +136,27 @@ func TestBackupFilesystem(t *testing.T) {
130136
t.Logf("%+v", incr1)
131137
require.NoError(t, err)
132138

139+
// Update schema and types to make sure updates to the schema are backed up.
140+
require.NoError(t, dg.Alter(ctx, &api.Operation{Schema: `
141+
movie: string .
142+
actor: string .
143+
type Node {
144+
movie
145+
}
146+
type NewNode {
147+
actor
148+
}`}))
149+
133150
// Perform first incremental backup.
134151
_ = runBackup(t, 6, 2)
135152
restored = runRestore(t, copyBackupDir, "", incr1.Txn.CommitTs)
136153

154+
// Check the predicates and types in the schema are as expected.
155+
preds = append(preds, "actor")
156+
types = append(types, "NewNode")
157+
testutil.CheckSchema(t, preds, types)
158+
159+
// Perform some checks on the restored values.
137160
checks = []struct {
138161
blank, expected string
139162
}{
@@ -157,6 +180,7 @@ func TestBackupFilesystem(t *testing.T) {
157180
// Perform second incremental backup.
158181
_ = runBackup(t, 9, 3)
159182
restored = runRestore(t, copyBackupDir, "", incr2.Txn.CommitTs)
183+
testutil.CheckSchema(t, preds, types)
160184

161185
checks = []struct {
162186
blank, expected string
@@ -181,6 +205,7 @@ func TestBackupFilesystem(t *testing.T) {
181205
// Perform second full backup.
182206
dirs := runBackupInternal(t, true, 12, 4)
183207
restored = runRestore(t, copyBackupDir, "", incr3.Txn.CommitTs)
208+
testutil.CheckSchema(t, preds, types)
184209

185210
// Check all the values were restored to their most recent value.
186211
checks = []struct {
@@ -279,16 +304,6 @@ func runRestore(t *testing.T, backupLocation, lastDir string, commitTs uint64) m
279304
restored, err := testutil.GetPredicateValues(pdir, "movie", commitTs)
280305
require.NoError(t, err)
281306
t.Logf("--- Restored values: %+v\n", restored)
282-
283-
restoredPreds, err := testutil.GetPredicateNames(pdir, commitTs)
284-
require.NoError(t, err)
285-
require.ElementsMatch(t, []string{"dgraph.graphql.schema", "dgraph.graphql.xid", "dgraph.type",
286-
"movie"}, restoredPreds)
287-
288-
restoredTypes, err := testutil.GetTypeNames(pdir, commitTs)
289-
require.NoError(t, err)
290-
require.ElementsMatch(t, []string{"Node", "dgraph.graphql"}, restoredTypes)
291-
292307
return restored
293308
}
294309

systest/backup/minio/backup_test.go

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ func TestBackupMinio(t *testing.T) {
112112
_ = runBackup(t, 3, 1)
113113
restored := runRestore(t, "", math.MaxUint64)
114114

115+
// Check the predicates and types in the schema are as expected.
116+
// TODO: refactor tests so that minio and filesystem tests share most of their logic.
117+
preds := []string{"dgraph.graphql.schema", "dgraph.graphql.xid", "dgraph.type", "movie"}
118+
types := []string{"Node", "dgraph.graphql"}
119+
testutil.CheckSchema(t, preds, types)
120+
115121
checks := []struct {
116122
blank, expected string
117123
}{
@@ -136,10 +142,26 @@ func TestBackupMinio(t *testing.T) {
136142
t.Logf("%+v", incr1)
137143
require.NoError(t, err)
138144

145+
// Update schema and types to make sure updates to the schema are backed up.
146+
require.NoError(t, dg.Alter(ctx, &api.Operation{Schema: `
147+
movie: string .
148+
actor: string .
149+
type Node {
150+
movie
151+
}
152+
type NewNode {
153+
actor
154+
}`}))
155+
139156
// Perform first incremental backup.
140157
_ = runBackup(t, 6, 2)
141158
restored = runRestore(t, "", incr1.Txn.CommitTs)
142159

160+
// Check the predicates and types in the schema are as expected.
161+
preds = append(preds, "actor")
162+
types = append(types, "NewNode")
163+
testutil.CheckSchema(t, preds, types)
164+
143165
checks = []struct {
144166
blank, expected string
145167
}{
@@ -163,6 +185,7 @@ func TestBackupMinio(t *testing.T) {
163185
// Perform second incremental backup.
164186
_ = runBackup(t, 9, 3)
165187
restored = runRestore(t, "", incr2.Txn.CommitTs)
188+
testutil.CheckSchema(t, preds, types)
166189

167190
checks = []struct {
168191
blank, expected string
@@ -187,6 +210,7 @@ func TestBackupMinio(t *testing.T) {
187210
// Perform second full backup.
188211
dirs := runBackupInternal(t, true, 12, 4)
189212
restored = runRestore(t, "", incr3.Txn.CommitTs)
213+
testutil.CheckSchema(t, preds, types)
190214

191215
// Check all the values were restored to their most recent value.
192216
checks = []struct {
@@ -285,20 +309,8 @@ func runRestore(t *testing.T, lastDir string, commitTs uint64) map[string]string
285309
}
286310
pdir := "./data/restore/p1"
287311
restored, err := testutil.GetPredicateValues(pdir, "movie", commitTs)
288-
require.NoError(t, err)
289-
290-
restoredPreds, err := testutil.GetPredicateNames(pdir, commitTs)
291-
require.NoError(t, err)
292-
require.ElementsMatch(t, []string{"dgraph.graphql.schema", "dgraph.graphql.xid", "dgraph.type",
293-
"movie"}, restoredPreds)
294-
295-
restoredTypes, err := testutil.GetTypeNames(pdir, commitTs)
296-
require.NoError(t, err)
297-
require.ElementsMatch(t, []string{"Node", "dgraph.graphql"}, restoredTypes)
298-
299312
require.NoError(t, err)
300313
t.Logf("--- Restored values: %+v\n", restored)
301-
302314
return restored
303315
}
304316

testutil/backup.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package testutil
1818

1919
import (
2020
"fmt"
21+
"testing"
2122

2223
"github.com/dgraph-io/badger/v2"
2324
"github.com/dgraph-io/badger/v2/options"
@@ -26,6 +27,8 @@ import (
2627
"github.com/dgraph-io/dgraph/protos/pb"
2728
"github.com/dgraph-io/dgraph/types"
2829
"github.com/dgraph-io/dgraph/x"
30+
31+
"github.com/stretchr/testify/require"
2932
)
3033

3134
// KEYFILE is set to the path of the file containing the key. Used for testing purposes only.
@@ -134,11 +137,32 @@ func readSchema(pdir string, dType dataType) ([]string, error) {
134137
}
135138

136139
// GetPredicateNames returns the list of all the predicates stored in the restored pdir.
137-
func GetPredicateNames(pdir string, readTs uint64) ([]string, error) {
140+
func GetPredicateNames(pdir string) ([]string, error) {
138141
return readSchema(pdir, schemaPredicate)
139142
}
140143

141144
// GetTypeNames returns the list of all the types stored in the restored pdir.
142-
func GetTypeNames(pdir string, readTs uint64) ([]string, error) {
145+
func GetTypeNames(pdir string) ([]string, error) {
143146
return readSchema(pdir, schemaType)
144147
}
148+
149+
// CheckSchema checks the names of the predicates and types in the schema against the given names.
150+
func CheckSchema(t *testing.T, preds, types []string) {
151+
pdirs := []string{
152+
"./data/restore/p1",
153+
"./data/restore/p2",
154+
"./data/restore/p3",
155+
}
156+
157+
restoredPreds := make([]string, 0)
158+
for _, pdir := range pdirs {
159+
groupPreds, err := GetPredicateNames(pdir)
160+
require.NoError(t, err)
161+
restoredPreds = append(restoredPreds, groupPreds...)
162+
163+
restoredTypes, err := GetTypeNames(pdir)
164+
require.NoError(t, err)
165+
require.ElementsMatch(t, types, restoredTypes)
166+
}
167+
require.ElementsMatch(t, preds, restoredPreds)
168+
}

worker/backup_processor.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,12 @@ func (pr *BackupProcessor) toBackupList(key []byte, itr *badger.Iterator) (*bpb.
233233
list := &bpb.KVList{}
234234

235235
item := itr.Item()
236-
if item.Version() < pr.Request.SinceTs || item.IsDeletedOrExpired() {
236+
if item.UserMeta() != posting.BitSchemaPosting && (item.Version() < pr.Request.SinceTs ||
237+
item.IsDeletedOrExpired()) {
237238
// Ignore versions less than given timestamp, or skip older versions of
238239
// the given key by returning an empty list.
240+
// Do not do this for schema and type keys. Those keys always have a
241+
// version of one so they would be incorrectly rejected by above check.
239242
return list, nil
240243
}
241244

worker/restore.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ func loadFromBackup(db *badger.DB, r io.Reader, preds predicateSet) (uint64, err
8484
br := bufio.NewReaderSize(r, 16<<10)
8585
unmarshalBuf := make([]byte, 1<<10)
8686

87+
// Delete schemas and types. Each backup file should have a complete copy of the schema.
88+
if err := db.DropPrefix([]byte{x.ByteSchema}); err != nil {
89+
return 0, err
90+
}
91+
if err := db.DropPrefix([]byte{x.ByteType}); err != nil {
92+
return 0, err
93+
}
94+
8795
loader := db.NewKVLoader(16)
8896
var maxUid uint64
8997
for {

0 commit comments

Comments
 (0)