-
Notifications
You must be signed in to change notification settings - Fork 16
/
datapagemap.c
126 lines (103 loc) · 2.54 KB
/
datapagemap.c
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*-------------------------------------------------------------------------
*
* datapagemap.c
* A data structure for keeping track of data pages that have changed.
*
* This is a fairly simple bitmap.
*
* Copyright (c) 2013-2020, PostgreSQL Global Development Group
* Copyright (c) 2019-2020, Postgres Professional
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "datapagemap.h"
struct datapagemap_iterator
{
datapagemap_t *map;
BlockNumber nextblkno;
};
/*
* Add a block to the bitmap.
*/
void
datapagemap_add(datapagemap_t *map, BlockNumber blkno)
{
int offset;
int bitno;
offset = blkno / 8;
bitno = blkno % 8;
/* enlarge or create bitmap if needed */
if (map->bitmapsize <= offset)
{
int oldsize = map->bitmapsize;
int newsize;
/*
* The minimum to hold the new bit is offset + 1. But add some
* headroom, so that we don't need to repeatedly enlarge the bitmap in
* the common case that blocks are modified in order, from beginning
* of a relation to the end.
*/
newsize = offset + 1;
newsize += 10;
if (map->bitmap != NULL)
map->bitmap = repalloc(map->bitmap, newsize);
else
map->bitmap = palloc(newsize);
/* zero out the newly allocated region */
memset(&map->bitmap[oldsize], 0, newsize - oldsize);
map->bitmapsize = newsize;
}
/* Set the bit */
map->bitmap[offset] |= (1 << bitno);
}
/*
* Start iterating through all entries in the page map.
*
* After datapagemap_iterate, call datapagemap_next to return the entries,
* until it returns false. After you're done, use pg_free() to destroy the
* iterator.
*/
datapagemap_iterator_t *
datapagemap_iterate(datapagemap_t *map)
{
datapagemap_iterator_t *iter;
iter = palloc(sizeof(datapagemap_iterator_t));
iter->map = map;
iter->nextblkno = 0;
return iter;
}
bool
datapagemap_next(datapagemap_iterator_t *iter, BlockNumber *blkno)
{
datapagemap_t *map = iter->map;
for (;;)
{
BlockNumber blk = iter->nextblkno;
int nextoff = blk / 8;
int bitno = blk % 8;
if (nextoff >= map->bitmapsize)
break;
iter->nextblkno++;
if (map->bitmap[nextoff] & (1 << bitno))
{
*blkno = blk;
return true;
}
}
/* no more set bits in this bitmap. */
return false;
}
/*
* A debugging aid. Prints out the contents of the page map.
*/
void
datapagemap_print(datapagemap_t *map)
{
datapagemap_iterator_t *iter;
BlockNumber blocknum;
iter = datapagemap_iterate(map);
while (datapagemap_next(iter, &blocknum))
elog(DEBUG3, "block %u", blocknum);
pfree(iter);
}