blob: 19a963fb1032a4537462b1f1c36df2b61010b782 [file] [log] [blame]
// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package dash
import (
"fmt"
"net/http"
"golang.org/x/net/context"
"google.golang.org/appengine/datastore"
"google.golang.org/appengine/log"
)
// dropNamespace drops all entities related to a single namespace.
// Use with care. There is no undo.
// This functionality is intentionally not connected to any handler.
// To use it, first make a backup of the datastore. Then, specify the target
// namespace in the ns variable, connect the function to a handler, invoke it
// and double check the output. Finally, set dryRun to false and invoke again.
func dropNamespace(c context.Context, w http.ResponseWriter, r *http.Request) error {
ns := "non-existent"
dryRun := true
if !dryRun {
log.Criticalf(c, "dropping namespace %v", ns)
}
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
fmt.Fprintf(w, "dropping namespace %v\n", ns)
if err := dropNamespaceReportingState(c, w, ns, dryRun); err != nil {
return err
}
type Entity struct {
name string
child string
}
entities := []Entity{
{textPatch, ""},
{textReproC, ""},
{textReproSyz, ""},
{textKernelConfig, ""},
{"Job", ""},
{textError, ""},
{textCrashLog, ""},
{textCrashReport, ""},
{"Build", ""},
{"Manager", "ManagerStats"},
{"Bug", "Crash"},
}
for _, entity := range entities {
keys, err := datastore.NewQuery(entity.name).
Filter("Namespace=", ns).
KeysOnly().
GetAll(c, nil)
if err != nil {
return err
}
fmt.Fprintf(w, "%v: %v\n", entity.name, len(keys))
if entity.child != "" {
var childKeys []*datastore.Key
for _, key := range keys {
keys1, err := datastore.NewQuery(entity.child).
Ancestor(key).
KeysOnly().
GetAll(c, nil)
if err != nil {
return err
}
childKeys = append(childKeys, keys1...)
}
fmt.Fprintf(w, " %v: %v\n", entity.child, len(childKeys))
if err := dropEntities(c, childKeys, dryRun); err != nil {
return err
}
}
if err := dropEntities(c, keys, dryRun); err != nil {
return err
}
}
return nil
}
var _ = dropNamespace // prevent warnings about dead code
func dropNamespaceReportingState(c context.Context, w http.ResponseWriter, ns string, dryRun bool) error {
tx := func(c context.Context) error {
state, err := loadReportingState(c)
if err != nil {
return err
}
newState := new(ReportingState)
for _, ent := range state.Entries {
if ent.Namespace != ns {
newState.Entries = append(newState.Entries, ent)
}
}
if !dryRun {
if err := saveReportingState(c, newState); err != nil {
return err
}
}
fmt.Fprintf(w, "ReportingState: %v\n", len(state.Entries)-len(newState.Entries))
return nil
}
return datastore.RunInTransaction(c, tx, nil)
}
func dropEntities(c context.Context, keys []*datastore.Key, dryRun bool) error {
if dryRun {
return nil
}
for len(keys) != 0 {
batch := 100
if batch > len(keys) {
batch = len(keys)
}
if err := datastore.DeleteMulti(c, keys[:batch]); err != nil {
return err
}
keys = keys[batch:]
}
return nil
}