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

fix(enterprise): Set version correctly post marshalling during restore #7018

Merged
merged 9 commits into from
Dec 2, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions posting/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,8 @@ func (out *rollupOutput) marshalPostingListPart(alloc *z.Allocator,
return kv, nil
}

// MarshalPostingList returns a KV with the marshalled posting list. The caller
// SHOULD SET the Key and Version for the returned KV.
func MarshalPostingList(plist *pb.PostingList, alloc *z.Allocator) *bpb.KV {
kv := y.NewKV(alloc)
if isPlistEmpty(plist) {
Expand Down
95 changes: 87 additions & 8 deletions systest/backup/filesystem/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,87 @@ import (
)

var (
copyBackupDir = "./data/backups_copy"
restoreDir = "./data/restore"
testDirs = []string{restoreDir}

alphaBackupDir = "/data/backups"

copyBackupDir = "./data/backups_copy"
restoreDir = "./data/restore"
testDirs = []string{restoreDir, exporterDir}
exporterDir = "data/exporter"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see exporterDir being used anywhere. Why do we have it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, cleaned it up

alphaBackupDir = "/data/backups"
oldBackupDir = "/data/to_restore"
alphaContainers = []string{
"alpha1",
"alpha2",
"alpha3",
}
)

func sendRestoreRequest(t *testing.T, location string) int {
if location == "" {
location = "/data/backup"
}
params := testutil.GraphQLParams{
Query: `mutation restore($location: String!) {
restore(input: {location: $location}) {
code
message
restoreId
}
}`,
Variables: map[string]interface{}{
"location": location,
},
}
resp := testutil.MakeGQLRequest(t, &params)
resp.RequireNoGraphQLErrors(t)

var restoreResp struct {
Restore struct {
Code string
Message string
RestoreId int
}
}

require.NoError(t, json.Unmarshal(resp.Data, &restoreResp))
require.Equal(t, restoreResp.Restore.Code, "Success")
require.Greater(t, restoreResp.Restore.RestoreId, 0)
return restoreResp.Restore.RestoreId
}

// This test takes a backup and then restores an old backup in a cluster incrementally.
// Next, cleans up the cluster and tries restoring the backups above.
func TestBackupOfOldRestore(t *testing.T) {
rahulgurnani marked this conversation as resolved.
Show resolved Hide resolved
dirSetup(t)
copyOldBackupDir(t)

dg, err := testutil.DgraphClient(testutil.SockAddr)
x.Check(err)
rahulgurnani marked this conversation as resolved.
Show resolved Hide resolved
ctx := context.Background()

require.NoError(t, dg.Alter(ctx, &api.Operation{DropAll: true}))
rahulgurnani marked this conversation as resolved.
Show resolved Hide resolved
time.Sleep(2 * time.Second)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please confirm that these sleeps are good enough by running the tests multiple times. Otherwise these can be flaky.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Ran it 10 times locally.


_ = runBackup(t, 3, 1)

_ = sendRestoreRequest(t, oldBackupDir)
time.Sleep(3 * time.Second)

resp, err := dg.NewTxn().Query(context.Background(), `{ authors(func: has(Author.name)) { count(uid) } }`)
x.Check(err)
rahulgurnani marked this conversation as resolved.
Show resolved Hide resolved
require.JSONEq(t, "{\"authors\":[{\"count\":1}]}", string(resp.Json))

_ = runBackup(t, 6, 2)

// Clean the cluster and try restoring the backups created above.
require.NoError(t, dg.Alter(ctx, &api.Operation{DropAll: true}))
time.Sleep(2 * time.Second)
_ = sendRestoreRequest(t, alphaBackupDir)
time.Sleep(3 * time.Second)

resp, err = dg.NewTxn().Query(context.Background(), `{ authors(func: has(Author.name)) { count(uid) } }`)
x.Check(err)
rahulgurnani marked this conversation as resolved.
Show resolved Hide resolved
require.JSONEq(t, "{\"authors\":[{\"count\":1}]}", string(resp.Json))
}

func TestBackupFilesystem(t *testing.T) {
conn, err := grpc.Dial(testutil.SockAddr, grpc.WithInsecure())
require.NoError(t, err)
Expand Down Expand Up @@ -330,7 +398,7 @@ func runBackupInternal(t *testing.T, forceFull bool, numExpectedFiles,
copyToLocalFs(t)

files := x.WalkPathFunc(copyBackupDir, func(path string, isdir bool) bool {
return !isdir && strings.HasSuffix(path, ".backup")
return !isdir && strings.HasSuffix(path, ".backup") && strings.HasPrefix(path, "data/backups_copy/dgraph.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use copyBackupDir instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would not help because copyBackupDir = ./data/backups_copy

})
require.Equal(t, numExpectedFiles, len(files))

Expand All @@ -340,7 +408,7 @@ func runBackupInternal(t *testing.T, forceFull bool, numExpectedFiles,
require.Equal(t, numExpectedDirs, len(dirs))

manifests := x.WalkPathFunc(copyBackupDir, func(path string, isdir bool) bool {
return !isdir && strings.Contains(path, "manifest.json")
return !isdir && strings.Contains(path, "manifest.json") && strings.HasPrefix(path, "data/backups_copy/dgraph.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use copyBackupDir instead.

})
require.Equal(t, numExpectedDirs, len(manifests))

Expand Down Expand Up @@ -403,6 +471,9 @@ func dirCleanup(t *testing.T) {
if err := os.RemoveAll(restoreDir); err != nil {
t.Fatalf("Error removing directory: %s", err.Error())
}
if err := os.RemoveAll(exporterDir); err != nil {
t.Fatalf("Error removing directory: %s", err.Error())
}
if err := os.RemoveAll(copyBackupDir); err != nil {
t.Fatalf("Error removing directory: %s", err.Error())
}
Expand All @@ -413,6 +484,14 @@ func dirCleanup(t *testing.T) {
}
}

func copyOldBackupDir(t *testing.T) {
destPath := testutil.DockerPrefix + "_alpha1_1:/data"
srchPath := "." + oldBackupDir
if err := testutil.DockerCp(srchPath, destPath); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

require.NoError please

t.Fatalf("Error copying files from docker container: %s", err.Error())
}
}

func copyToLocalFs(t *testing.T) {
// The original backup files are not accessible because docker creates all files in
// the shared volume as the root user. This restriction is circumvented by using
Expand Down
10 changes: 7 additions & 3 deletions worker/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,14 @@ func loadFromBackup(db *badger.DB, r io.Reader, restoreTs uint64, preds predicat
// part without rolling the key first. This part is here for backwards
// compatibility. New backups are not affected because there was a change
// to roll up lists into a single one.
kv := posting.MarshalPostingList(pl, nil)
newKv := posting.MarshalPostingList(pl, nil)
codec.FreePack(pl.Pack)
kv.Key = restoreKey
if err := loader.Set(kv); err != nil {
newKv.Key = restoreKey
// Use the version of the KV before we marshalled the
// posting list. The MarshalPostingList function returns KV
// with a zero version.
newKv.Version = kv.Version
if err := loader.Set(newKv); err != nil {
return 0, err
}
} else {
Expand Down