1 /*-------------------------------------------------------------------------
2  *
3  * gindesc.c
4  *	  rmgr descriptor routines for access/transam/gin/ginxlog.c
5  *
6  * Portions Copyright (c) 1996-2018, 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