1 /*-
2 * Copyright (c) 2014-2018 MongoDB, Inc.
3 * Copyright (c) 2008-2014 WiredTiger, Inc.
4 * All rights reserved.
5 *
6 * See the file LICENSE for redistribution information.
7 */
8
9 #include "util.h"
10
11 static int list_get_allocsize(WT_SESSION *, const char *, size_t *);
12 static int list_print(WT_SESSION *, const char *, bool, bool);
13 static int list_print_checkpoint(WT_SESSION *, const char *);
14 static int usage(void);
15
16 int
util_list(WT_SESSION * session,int argc,char * argv[])17 util_list(WT_SESSION *session, int argc, char *argv[])
18 {
19 WT_DECL_RET;
20 int ch;
21 char *uri;
22 bool cflag, vflag;
23
24 cflag = vflag = false;
25 uri = NULL;
26 while ((ch = __wt_getopt(progname, argc, argv, "cv")) != EOF)
27 switch (ch) {
28 case 'c':
29 cflag = true;
30 break;
31 case 'v':
32 vflag = true;
33 break;
34 case '?':
35 default:
36 return (usage());
37 }
38 argc -= __wt_optind;
39 argv += __wt_optind;
40
41 switch (argc) {
42 case 0:
43 break;
44 case 1:
45 if ((uri = util_uri(session, *argv, "table")) == NULL)
46 return (1);
47 break;
48 default:
49 return (usage());
50 }
51
52 ret = list_print(session, uri, cflag, vflag);
53
54 free(uri);
55 return (ret);
56 }
57
58 /*
59 * list_get_allocsize --
60 * Get the allocation size for this file from the metadata.
61 */
62 static int
list_get_allocsize(WT_SESSION * session,const char * key,size_t * allocsize)63 list_get_allocsize(WT_SESSION *session, const char *key, size_t *allocsize)
64 {
65 WT_CONFIG_ITEM szvalue;
66 WT_CONFIG_PARSER *parser;
67 WT_DECL_RET;
68 WT_EXTENSION_API *wt_api;
69 int tret;
70 char *config;
71
72 wt_api = session->connection->get_extension_api(session->connection);
73 if ((ret = wt_api->metadata_search(wt_api, session, key, &config)) != 0)
74 return (util_err(
75 session, ret, "%s: WT_EXTENSION_API.metadata_search", key));
76 if ((ret = wt_api->config_parser_open(wt_api, session, config,
77 strlen(config), &parser)) != 0)
78 return (util_err(
79 session, ret, "WT_EXTENSION_API.config_parser_open"));
80 if ((ret = parser->get(parser, "allocation_size", &szvalue)) != 0) {
81 if (ret == WT_NOTFOUND) {
82 *allocsize = 0;
83 ret = 0;
84 } else
85 ret = util_err(session, ret, "WT_CONFIG_PARSER.get");
86 if ((tret = parser->close(parser)) != 0)
87 (void)util_err(session, tret, "WT_CONFIG_PARSER.close");
88 return (ret);
89 }
90 if ((ret = parser->close(parser)) != 0)
91 return (util_err(session, ret, "WT_CONFIG_PARSER.close"));
92 *allocsize = (size_t)szvalue.val;
93 return (0);
94 }
95
96 /*
97 * list_print --
98 * List the high-level objects in the database.
99 */
100 static int
list_print(WT_SESSION * session,const char * uri,bool cflag,bool vflag)101 list_print(WT_SESSION *session, const char *uri, bool cflag, bool vflag)
102 {
103 WT_CURSOR *cursor;
104 WT_DECL_RET;
105 const char *key, *value;
106 bool found;
107
108 /* Open the metadata file. */
109 if ((ret = session->open_cursor(
110 session, WT_METADATA_URI, NULL, NULL, &cursor)) != 0) {
111 /*
112 * If there is no metadata (yet), this will return ENOENT.
113 * Treat that the same as an empty metadata.
114 */
115 if (ret == ENOENT)
116 return (0);
117
118 return (util_err(session,
119 ret, "%s: WT_SESSION.open_cursor", WT_METADATA_URI));
120 }
121
122 found = uri == NULL;
123 while ((ret = cursor->next(cursor)) == 0) {
124 /* Get the key. */
125 if ((ret = cursor->get_key(cursor, &key)) != 0)
126 return (util_cerr(cursor, "get_key", ret));
127
128 /*
129 * If a name is specified, only show objects that match.
130 */
131 if (uri != NULL) {
132 if (!WT_PREFIX_MATCH(key, uri))
133 continue;
134 found = true;
135 }
136
137 /*
138 * !!!
139 * We don't normally say anything about the WiredTiger metadata
140 * and lookaside tables, they're not application/user "objects"
141 * in the database. I'm making an exception for the checkpoint
142 * and verbose options. However, skip over the metadata system
143 * information for anything except the verbose option.
144 */
145 if (!vflag && WT_PREFIX_MATCH(key, WT_SYSTEM_PREFIX))
146 continue;
147 if (cflag || vflag ||
148 (strcmp(key, WT_METADATA_URI) != 0 &&
149 strcmp(key, WT_LAS_URI) != 0))
150 printf("%s\n", key);
151
152 if (!cflag && !vflag)
153 continue;
154
155 if (cflag && (ret = list_print_checkpoint(session, key)) != 0)
156 return (ret);
157 if (vflag) {
158 if ((ret = cursor->get_value(cursor, &value)) != 0)
159 return (util_cerr(cursor, "get_value", ret));
160 printf("%s\n", value);
161 }
162 }
163 if (ret != WT_NOTFOUND)
164 return (util_cerr(cursor, "next", ret));
165 if (!found) {
166 fprintf(stderr, "%s: %s: not found\n", progname, uri);
167 return (1);
168 }
169
170 return (0);
171 }
172
173 /*
174 * list_print_checkpoint --
175 * List the checkpoint information.
176 */
177 static int
list_print_checkpoint(WT_SESSION * session,const char * key)178 list_print_checkpoint(WT_SESSION *session, const char *key)
179 {
180 WT_BLOCK_CKPT ci;
181 WT_CKPT *ckpt, *ckptbase;
182 WT_DECL_RET;
183 size_t allocsize, len;
184 time_t t;
185 uint64_t v;
186
187 /*
188 * We may not find any checkpoints for this file, in which case we don't
189 * report an error, and continue our caller's loop. Otherwise, read the
190 * list of checkpoints and print each checkpoint's name and time.
191 */
192 if ((ret = __wt_metadata_get_ckptlist(session, key, &ckptbase)) != 0)
193 return (ret == WT_NOTFOUND ? 0 : ret);
194
195 /* We need the allocation size for decoding the checkpoint addr */
196 if ((ret = list_get_allocsize(session, key, &allocsize)) != 0)
197 return (ret);
198
199 /* Find the longest name, so we can pretty-print. */
200 len = 0;
201 WT_CKPT_FOREACH(ckptbase, ckpt)
202 if (strlen(ckpt->name) > len)
203 len = strlen(ckpt->name);
204 ++len;
205
206 memset(&ci, 0, sizeof(ci));
207 WT_CKPT_FOREACH(ckptbase, ckpt) {
208 if (allocsize != 0 && (ret = __wt_block_ckpt_decode(
209 session, allocsize, ckpt->raw.data, &ci)) != 0) {
210 (void)util_err(session, ret, "__wt_block_ckpt_decode");
211 /* continue if damaged */
212 ci.root_size = 0;
213 }
214 /*
215 * Call ctime, not ctime_r; ctime_r has portability problems,
216 * the Solaris version is different from the POSIX standard.
217 */
218 t = (time_t)ckpt->sec;
219 printf("\t%*s: %.24s", (int)len, ckpt->name, ctime(&t));
220
221 v = ckpt->ckpt_size;
222 if (v >= WT_PETABYTE)
223 printf(" (%" PRIu64 " PB)\n", v / WT_PETABYTE);
224 else if (v >= WT_TERABYTE)
225 printf(" (%" PRIu64 " TB)\n", v / WT_TERABYTE);
226 else if (v >= WT_GIGABYTE)
227 printf(" (%" PRIu64 " GB)\n", v / WT_GIGABYTE);
228 else if (v >= WT_MEGABYTE)
229 printf(" (%" PRIu64 " MB)\n", v / WT_MEGABYTE);
230 else if (v >= WT_KILOBYTE)
231 printf(" (%" PRIu64 " KB)\n", v / WT_KILOBYTE);
232 else
233 printf(" (%" PRIu64 " B)\n", v);
234 if (ci.root_size != 0) {
235 printf("\t\t" "root offset: %" PRIuMAX
236 " (0x%" PRIxMAX ")\n",
237 (uintmax_t)ci.root_offset,
238 (uintmax_t)ci.root_offset);
239 printf("\t\t" "root size: %" PRIu32
240 " (0x%" PRIx32 ")\n",
241 ci.root_size, ci.root_size);
242 printf("\t\t" "root checksum: %" PRIu32
243 " (0x%" PRIx32 ")\n",
244 ci.root_checksum, ci.root_checksum);
245 }
246 }
247
248 __wt_metadata_free_ckptlist(session, ckptbase);
249 return (0);
250 }
251
252 static int
usage(void)253 usage(void)
254 {
255 (void)fprintf(stderr,
256 "usage: %s %s "
257 "list [-cv] [uri]\n",
258 progname, usage_prefix);
259 return (1);
260 }
261