1 /*-------------------------------------------------------------------------
2 *
3 * gindesc.c
4 * rmgr descriptor routines for access/transam/gin/ginxlog.c
5 *
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/access/rmgrdesc/gindesc.c
12 *
13 *-------------------------------------------------------------------------
14 */
15 #include "postgres.h"
16
17 #include "access/ginxlog.h"
18 #include "access/xlogutils.h"
19 #include "lib/stringinfo.h"
20 #include "storage/relfilenode.h"
21
22 static void
desc_recompress_leaf(StringInfo buf,ginxlogRecompressDataLeaf * insertData)23 desc_recompress_leaf(StringInfo buf, ginxlogRecompressDataLeaf *insertData)
24 {
25 int i;
26 char *walbuf = ((char *) insertData) + sizeof(ginxlogRecompressDataLeaf);
27
28 appendStringInfo(buf, " %d segments:", (int) insertData->nactions);
29
30 for (i = 0; i < insertData->nactions; i++)
31 {
32 uint8 a_segno = *((uint8 *) (walbuf++));
33 uint8 a_action = *((uint8 *) (walbuf++));
34 uint16 nitems = 0;
35 int newsegsize = 0;
36
37 if (a_action == GIN_SEGMENT_INSERT ||
38 a_action == GIN_SEGMENT_REPLACE)
39 {
40 newsegsize = SizeOfGinPostingList((GinPostingList *) walbuf);
41 walbuf += SHORTALIGN(newsegsize);
42 }
43
44 if (a_action == GIN_SEGMENT_ADDITEMS)
45 {
46 memcpy(&nitems, walbuf, sizeof(uint16));
47 walbuf += sizeof(uint16);
48 walbuf += nitems * sizeof(ItemPointerData);
49 }
50
51 switch (a_action)
52 {
53 case GIN_SEGMENT_ADDITEMS:
54 appendStringInfo(buf, " %d (add %d items)", a_segno, nitems);
55 break;
56 case GIN_SEGMENT_DELETE:
57 appendStringInfo(buf, " %d (delete)", a_segno);
58 break;
59 case GIN_SEGMENT_INSERT:
60 appendStringInfo(buf, " %d (insert)", a_segno);
61 break;
62 case GIN_SEGMENT_REPLACE:
63 appendStringInfo(buf, " %d (replace)", a_segno);
64 break;
65 default:
66 appendStringInfo(buf, " %d unknown action %d ???", a_segno, a_action);
67 /* cannot decode unrecognized actions further */
68 return;
69 }
70 }
71 }
72
73 void
gin_desc(StringInfo buf,XLogReaderState * record)74 gin_desc(StringInfo buf, XLogReaderState *record)
75 {
76 char *rec = XLogRecGetData(record);
77 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
78
79 switch (info)
80 {
81 case XLOG_GIN_CREATE_INDEX:
82 /* no further information */
83 break;
84 case XLOG_GIN_CREATE_PTREE:
85 /* no further information */
86 break;
87 case XLOG_GIN_INSERT:
88 {
89 ginxlogInsert *xlrec = (ginxlogInsert *) rec;
90
91 appendStringInfo(buf, "isdata: %c isleaf: %c",
92 (xlrec->flags & GIN_INSERT_ISDATA) ? 'T' : 'F',
93 (xlrec->flags & GIN_INSERT_ISLEAF) ? 'T' : 'F');
94 if (!(xlrec->flags & GIN_INSERT_ISLEAF))
95 {
96 char *payload = rec + sizeof(ginxlogInsert);
97 BlockNumber leftChildBlkno;
98 BlockNumber rightChildBlkno;
99
100 leftChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
101 payload += sizeof(BlockIdData);
102 rightChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
103 payload += sizeof(BlockNumber);
104 appendStringInfo(buf, " children: %u/%u",
105 leftChildBlkno, rightChildBlkno);
106 }
107 if (XLogRecHasBlockImage(record, 0))
108 {
109 if (XLogRecBlockImageApply(record, 0))
110 appendStringInfoString(buf, " (full page image)");
111 else
112 appendStringInfoString(buf, " (full page image, for WAL verification)");
113 }
114 else
115 {
116 char *payload = XLogRecGetBlockData(record, 0, NULL);
117
118 if (!(xlrec->flags & GIN_INSERT_ISDATA))
119 appendStringInfo(buf, " isdelete: %c",
120 (((ginxlogInsertEntry *) payload)->isDelete) ? 'T' : 'F');
121 else if (xlrec->flags & GIN_INSERT_ISLEAF)
122 desc_recompress_leaf(buf, (ginxlogRecompressDataLeaf *) payload);
123 else
124 {
125 ginxlogInsertDataInternal *insertData =
126 (ginxlogInsertDataInternal *) payload;
127
128 appendStringInfo(buf, " pitem: %u-%u/%u",
129 PostingItemGetBlockNumber(&insertData->newitem),
130 ItemPointerGetBlockNumber(&insertData->newitem.key),
131 ItemPointerGetOffsetNumber(&insertData->newitem.key));
132 }
133 }
134 }
135 break;
136 case XLOG_GIN_SPLIT:
137 {
138 ginxlogSplit *xlrec = (ginxlogSplit *) rec;
139
140 appendStringInfo(buf, "isrootsplit: %c",
141 (((ginxlogSplit *) rec)->flags & GIN_SPLIT_ROOT) ? 'T' : 'F');
142 appendStringInfo(buf, " isdata: %c isleaf: %c",
143 (xlrec->flags & GIN_INSERT_ISDATA) ? 'T' : 'F',
144 (xlrec->flags & GIN_INSERT_ISLEAF) ? 'T' : 'F');
145 }
146 break;
147 case XLOG_GIN_VACUUM_PAGE:
148 /* no further information */
149 break;
150 case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
151 {
152 if (XLogRecHasBlockImage(record, 0))
153 {
154 if (XLogRecBlockImageApply(record, 0))
155 appendStringInfoString(buf, " (full page image)");
156 else
157 appendStringInfoString(buf, " (full page image, for WAL verification)");
158 }
159 else
160 {
161 ginxlogVacuumDataLeafPage *xlrec =
162 (ginxlogVacuumDataLeafPage *) XLogRecGetBlockData(record, 0, NULL);
163
164 desc_recompress_leaf(buf, &xlrec->data);
165 }
166 }
167 break;
168 case XLOG_GIN_DELETE_PAGE:
169 /* no further information */
170 break;
171 case XLOG_GIN_UPDATE_META_PAGE:
172 /* no further information */
173 break;
174 case XLOG_GIN_INSERT_LISTPAGE:
175 /* no further information */
176 break;
177 case XLOG_GIN_DELETE_LISTPAGE:
178 appendStringInfo(buf, "ndeleted: %d",
179 ((ginxlogDeleteListPages *) rec)->ndeleted);
180 break;
181 }
182 }
183
184 const char *
gin_identify(uint8 info)185 gin_identify(uint8 info)
186 {
187 const char *id = NULL;
188
189 switch (info & ~XLR_INFO_MASK)
190 {
191 case XLOG_GIN_CREATE_INDEX:
192 id = "CREATE_INDEX";
193 break;
194 case XLOG_GIN_CREATE_PTREE:
195 id = "CREATE_PTREE";
196 break;
197 case XLOG_GIN_INSERT:
198 id = "INSERT";
199 break;
200 case XLOG_GIN_SPLIT:
201 id = "SPLIT";
202 break;
203 case XLOG_GIN_VACUUM_PAGE:
204 id = "VACUUM_PAGE";
205 break;
206 case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
207 id = "VACUUM_DATA_LEAF_PAGE";
208 break;
209 case XLOG_GIN_DELETE_PAGE:
210 id = "DELETE_PAGE";
211 break;
212 case XLOG_GIN_UPDATE_META_PAGE:
213 id = "UPDATE_META_PAGE";
214 break;
215 case XLOG_GIN_INSERT_LISTPAGE:
216 id = "INSERT_LISTPAGE";
217 break;
218 case XLOG_GIN_DELETE_LISTPAGE:
219 id = "DELETE_LISTPAGE";
220 break;
221 }
222
223 return id;
224 }
225