Deleting a very large list of keys will cause the freelist to use overflow.
(t *testing.T)
| 374 | |
| 375 | // Deleting a very large list of keys will cause the freelist to use overflow. |
| 376 | func TestBucket_Delete_FreelistOverflow(t *testing.T) { |
| 377 | if testing.Short() { |
| 378 | t.Skip("skipping test in short mode.") |
| 379 | } |
| 380 | |
| 381 | db := btesting.MustCreateDB(t) |
| 382 | |
| 383 | k := make([]byte, 16) |
| 384 | // The bigger the pages - the more values we need to write. |
| 385 | for i := uint64(0); i < 2*uint64(db.Info().PageSize); i++ { |
| 386 | if err := db.Update(func(tx *bolt.Tx) error { |
| 387 | b, err := tx.CreateBucketIfNotExists([]byte("0")) |
| 388 | if err != nil { |
| 389 | t.Fatalf("bucket error: %s", err) |
| 390 | } |
| 391 | |
| 392 | for j := uint64(0); j < 1000; j++ { |
| 393 | binary.BigEndian.PutUint64(k[:8], i) |
| 394 | binary.BigEndian.PutUint64(k[8:], j) |
| 395 | if err := b.Put(k, nil); err != nil { |
| 396 | t.Fatalf("put error: %s", err) |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | return nil |
| 401 | }); err != nil { |
| 402 | t.Fatal(err) |
| 403 | } |
| 404 | } |
| 405 | |
| 406 | // Delete all of them in one large transaction |
| 407 | if err := db.Update(func(tx *bolt.Tx) error { |
| 408 | b := tx.Bucket([]byte("0")) |
| 409 | c := b.Cursor() |
| 410 | for k, _ := c.First(); k != nil; k, _ = c.Next() { |
| 411 | if err := c.Delete(); err != nil { |
| 412 | t.Fatal(err) |
| 413 | } |
| 414 | } |
| 415 | return nil |
| 416 | }); err != nil { |
| 417 | t.Fatal(err) |
| 418 | } |
| 419 | |
| 420 | // Check more than an overflow's worth of pages are freed. |
| 421 | stats := db.Stats() |
| 422 | freePages := stats.FreePageN + stats.PendingPageN |
| 423 | if freePages <= 0xFFFF { |
| 424 | t.Fatalf("expected more than 0xFFFF free pages, got %v", freePages) |
| 425 | } |
| 426 | |
| 427 | // Free page count should be preserved on reopen. |
| 428 | db.MustClose() |
| 429 | db.MustReopen() |
| 430 | if reopenFreePages := db.Stats().FreePageN; freePages != reopenFreePages { |
| 431 | t.Fatalf("expected %d free pages, got %+v", freePages, db.Stats()) |
| 432 | } |
| 433 | if reopenPendingPages := db.Stats().PendingPageN; reopenPendingPages != 0 { |
nothing calls this directly
no test coverage detected