| 1 | /*------------------------------------------------------------------------- | 
|---|
| 2 | * | 
|---|
| 3 | * datapagemap.c | 
|---|
| 4 | *	  A data structure for keeping track of data pages that have changed. | 
|---|
| 5 | * | 
|---|
| 6 | * This is a fairly simple bitmap. | 
|---|
| 7 | * | 
|---|
| 8 | * Copyright (c) 2013-2019, PostgreSQL Global Development Group | 
|---|
| 9 | * | 
|---|
| 10 | *------------------------------------------------------------------------- | 
|---|
| 11 | */ | 
|---|
| 12 |  | 
|---|
| 13 | #include "postgres_fe.h" | 
|---|
| 14 |  | 
|---|
| 15 | #include "datapagemap.h" | 
|---|
| 16 |  | 
|---|
| 17 | #include "common/logging.h" | 
|---|
| 18 |  | 
|---|
| 19 | struct datapagemap_iterator | 
|---|
| 20 | { | 
|---|
| 21 | datapagemap_t *map; | 
|---|
| 22 | BlockNumber nextblkno; | 
|---|
| 23 | }; | 
|---|
| 24 |  | 
|---|
| 25 | /***** | 
|---|
| 26 | * Public functions | 
|---|
| 27 | */ | 
|---|
| 28 |  | 
|---|
| 29 | /* | 
|---|
| 30 | * Add a block to the bitmap. | 
|---|
| 31 | */ | 
|---|
| 32 | void | 
|---|
| 33 | datapagemap_add(datapagemap_t *map, BlockNumber blkno) | 
|---|
| 34 | { | 
|---|
| 35 | int			offset; | 
|---|
| 36 | int			bitno; | 
|---|
| 37 |  | 
|---|
| 38 | offset = blkno / 8; | 
|---|
| 39 | bitno = blkno % 8; | 
|---|
| 40 |  | 
|---|
| 41 | /* enlarge or create bitmap if needed */ | 
|---|
| 42 | if (map->bitmapsize <= offset) | 
|---|
| 43 | { | 
|---|
| 44 | int			oldsize = map->bitmapsize; | 
|---|
| 45 | int			newsize; | 
|---|
| 46 |  | 
|---|
| 47 | /* | 
|---|
| 48 | * The minimum to hold the new bit is offset + 1. But add some | 
|---|
| 49 | * headroom, so that we don't need to repeatedly enlarge the bitmap in | 
|---|
| 50 | * the common case that blocks are modified in order, from beginning | 
|---|
| 51 | * of a relation to the end. | 
|---|
| 52 | */ | 
|---|
| 53 | newsize = offset + 1; | 
|---|
| 54 | newsize += 10; | 
|---|
| 55 |  | 
|---|
| 56 | map->bitmap = pg_realloc(map->bitmap, newsize); | 
|---|
| 57 |  | 
|---|
| 58 | /* zero out the newly allocated region */ | 
|---|
| 59 | memset(&map->bitmap[oldsize], 0, newsize - oldsize); | 
|---|
| 60 |  | 
|---|
| 61 | map->bitmapsize = newsize; | 
|---|
| 62 | } | 
|---|
| 63 |  | 
|---|
| 64 | /* Set the bit */ | 
|---|
| 65 | map->bitmap[offset] |= (1 << bitno); | 
|---|
| 66 | } | 
|---|
| 67 |  | 
|---|
| 68 | /* | 
|---|
| 69 | * Start iterating through all entries in the page map. | 
|---|
| 70 | * | 
|---|
| 71 | * After datapagemap_iterate, call datapagemap_next to return the entries, | 
|---|
| 72 | * until it returns false. After you're done, use pg_free() to destroy the | 
|---|
| 73 | * iterator. | 
|---|
| 74 | */ | 
|---|
| 75 | datapagemap_iterator_t * | 
|---|
| 76 | datapagemap_iterate(datapagemap_t *map) | 
|---|
| 77 | { | 
|---|
| 78 | datapagemap_iterator_t *iter; | 
|---|
| 79 |  | 
|---|
| 80 | iter = pg_malloc(sizeof(datapagemap_iterator_t)); | 
|---|
| 81 | iter->map = map; | 
|---|
| 82 | iter->nextblkno = 0; | 
|---|
| 83 |  | 
|---|
| 84 | return iter; | 
|---|
| 85 | } | 
|---|
| 86 |  | 
|---|
| 87 | bool | 
|---|
| 88 | datapagemap_next(datapagemap_iterator_t *iter, BlockNumber *blkno) | 
|---|
| 89 | { | 
|---|
| 90 | datapagemap_t *map = iter->map; | 
|---|
| 91 |  | 
|---|
| 92 | for (;;) | 
|---|
| 93 | { | 
|---|
| 94 | BlockNumber blk = iter->nextblkno; | 
|---|
| 95 | int			nextoff = blk / 8; | 
|---|
| 96 | int			bitno = blk % 8; | 
|---|
| 97 |  | 
|---|
| 98 | if (nextoff >= map->bitmapsize) | 
|---|
| 99 | break; | 
|---|
| 100 |  | 
|---|
| 101 | iter->nextblkno++; | 
|---|
| 102 |  | 
|---|
| 103 | if (map->bitmap[nextoff] & (1 << bitno)) | 
|---|
| 104 | { | 
|---|
| 105 | *blkno = blk; | 
|---|
| 106 | return true; | 
|---|
| 107 | } | 
|---|
| 108 | } | 
|---|
| 109 |  | 
|---|
| 110 | /* no more set bits in this bitmap. */ | 
|---|
| 111 | return false; | 
|---|
| 112 | } | 
|---|
| 113 |  | 
|---|
| 114 | /* | 
|---|
| 115 | * A debugging aid. Prints out the contents of the page map. | 
|---|
| 116 | */ | 
|---|
| 117 | void | 
|---|
| 118 | datapagemap_print(datapagemap_t *map) | 
|---|
| 119 | { | 
|---|
| 120 | datapagemap_iterator_t *iter; | 
|---|
| 121 | BlockNumber blocknum; | 
|---|
| 122 |  | 
|---|
| 123 | iter = datapagemap_iterate(map); | 
|---|
| 124 | while (datapagemap_next(iter, &blocknum)) | 
|---|
| 125 | pg_log_debug( "block %u", blocknum); | 
|---|
| 126 |  | 
|---|
| 127 | pg_free(iter); | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|