diff --git a/pkg/graphdb/graphdb.go b/pkg/graphdb/graphdb.go index c6f13eda27..b9433dbddc 100644 --- a/pkg/graphdb/graphdb.go +++ b/pkg/graphdb/graphdb.go @@ -378,12 +378,22 @@ func (db *Database) Purge(id string) (int, error) { tx.Rollback() return -1, err } - changes, err := rows.RowsAffected() if err != nil { return -1, err } + // Clear who's using this id as parent + refs, err := tx.Exec("DELETE FROM edge WHERE parent_id = ?;", id) + if err != nil { + tx.Rollback() + return -1, err + } + refsCount, err := refs.RowsAffected() + if err != nil { + return -1, err + } + // Delete entity if _, err := tx.Exec("DELETE FROM entity where id = ?;", id); err != nil { tx.Rollback() @@ -394,7 +404,7 @@ func (db *Database) Purge(id string) (int, error) { return -1, err } - return int(changes), nil + return int(changes + refsCount), nil } // Rename an edge for a given path diff --git a/pkg/graphdb/graphdb_test.go b/pkg/graphdb/graphdb_test.go index f22828560c..12dd524ed5 100644 --- a/pkg/graphdb/graphdb_test.go +++ b/pkg/graphdb/graphdb_test.go @@ -472,8 +472,8 @@ func TestPurgeId(t *testing.T) { db.Set("/webapp", "1") - if db.Refs("1") != 1 { - t.Fatal("Expect reference count to be 1") + if c := db.Refs("1"); c != 1 { + t.Fatalf("Expect reference count to be 1, got %d", c) } db.Set("/db", "2") @@ -484,7 +484,45 @@ func TestPurgeId(t *testing.T) { t.Fatal(err) } if count != 2 { - t.Fatal("Expected 2 references to be removed") + t.Fatalf("Expected 2 references to be removed, got %d", count) + } +} + +// Regression test https://github.com/docker/docker/issues/12334 +func TestPurgeIdRefPaths(t *testing.T) { + db, dbpath := newTestDb(t) + defer destroyTestDb(dbpath) + + db.Set("/webapp", "1") + db.Set("/db", "2") + + db.Set("/db/webapp", "1") + + if c := db.Refs("1"); c != 2 { + t.Fatalf("Expected 2 reference for webapp, got %d", c) + } + if c := db.Refs("2"); c != 1 { + t.Fatalf("Expected 1 reference for db, got %d", c) + } + + if rp := db.RefPaths("2"); len(rp) != 1 { + t.Fatalf("Expected 1 reference path for db, got %d", len(rp)) + } + + count, err := db.Purge("2") + if err != nil { + t.Fatal(err) + } + + if count != 2 { + t.Fatalf("Expected 2 rows to be removed, got %d", count) + } + + if c := db.Refs("2"); c != 0 { + t.Fatalf("Expected 0 reference for db, got %d", c) + } + if c := db.Refs("1"); c != 1 { + t.Fatalf("Expected 1 reference for webapp, got %d", c) } }