aboutsummaryrefslogtreecommitdiff
path: root/freelist_test.go
blob: 5948f3bd302471d58381ec17458069e90754f27d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package bolt

import (
	"testing"
	"unsafe"

	"github.com/stretchr/testify/assert"
)

// Ensure that a page is added to a transaction's freelist.
func TestFreelist_free(t *testing.T) {
	f := &freelist{pending: make(map[txid][]pgid)}
	f.free(100, &page{id: 12})
	assert.Equal(t, f.pending[100], []pgid{12})
}

// Ensure that a page and its overflow is added to a transaction's freelist.
func TestFreelist_free_overflow(t *testing.T) {
	f := &freelist{pending: make(map[txid][]pgid)}
	f.free(100, &page{id: 12, overflow: 3})
	assert.Equal(t, f.pending[100], []pgid{12, 13, 14, 15})
}

// Ensure that a transaction's free pages can be released.
func TestFreelist_release(t *testing.T) {
	f := &freelist{pending: make(map[txid][]pgid)}
	f.free(100, &page{id: 12, overflow: 1})
	f.free(100, &page{id: 9})
	f.free(102, &page{id: 39})
	f.release(100)
	f.release(101)
	assert.Equal(t, []pgid{9, 12, 13}, f.ids)
	f.release(102)
	assert.Equal(t, []pgid{9, 12, 13, 39}, f.ids)
}

// Ensure that a freelist can find contiguous blocks of pages.
func TestFreelist_allocate(t *testing.T) {
	f := &freelist{ids: []pgid{3, 4, 5, 6, 7, 9, 12, 13, 18}}
	assert.Equal(t, 3, int(f.allocate(3)))
	assert.Equal(t, 6, int(f.allocate(1)))
	assert.Equal(t, 0, int(f.allocate(3)))
	assert.Equal(t, 12, int(f.allocate(2)))
	assert.Equal(t, 7, int(f.allocate(1)))
	assert.Equal(t, 0, int(f.allocate(0)))
	assert.Equal(t, []pgid{9, 18}, f.ids)
	assert.Equal(t, 9, int(f.allocate(1)))
	assert.Equal(t, 18, int(f.allocate(1)))
	assert.Equal(t, 0, int(f.allocate(1)))
	assert.Equal(t, []pgid{}, f.ids)
}

// Ensure that a freelist can deserialize from a freelist page.
func TestFreelist_read(t *testing.T) {
	// Create a page.
	var buf [4096]byte
	page := (*page)(unsafe.Pointer(&buf[0]))
	page.flags = freelistPageFlag
	page.count = 2

	// Insert 2 page ids.
	ids := (*[3]pgid)(unsafe.Pointer(&page.ptr))
	ids[0] = 23
	ids[1] = 50

	// Deserialize page into a freelist.
	f := &freelist{pending: make(map[txid][]pgid)}
	f.read(page)

	// Ensure that there are two page ids in the freelist.
	assert.Equal(t, len(f.ids), 2)
	assert.Equal(t, f.ids[0], pgid(23))
	assert.Equal(t, f.ids[1], pgid(50))
}

// Ensure that a freelist can serialize into a freelist page.
func TestFreelist_write(t *testing.T) {
	// Create a freelist and write it to a page.
	var buf [4096]byte
	f := &freelist{ids: []pgid{12, 39}, pending: make(map[txid][]pgid)}
	f.pending[100] = []pgid{28, 11}
	f.pending[101] = []pgid{3}
	p := (*page)(unsafe.Pointer(&buf[0]))
	f.write(p)

	// Read the page back out.
	f2 := &freelist{pending: make(map[txid][]pgid)}
	f2.read(p)

	// Ensure that the freelist is correct.
	// All pages should be present and in reverse order.
	assert.Equal(t, len(f2.ids), 5)
	assert.Equal(t, f2.ids[0], pgid(3))
	assert.Equal(t, f2.ids[1], pgid(11))
	assert.Equal(t, f2.ids[2], pgid(12))
	assert.Equal(t, f2.ids[3], pgid(28))
	assert.Equal(t, f2.ids[4], pgid(39))
}