1 /* Copyright (C) 2014 InfiniDB, Inc.
2
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public License
5 as published by the Free Software Foundation; version 2 of
6 the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16 MA 02110-1301, USA. */
17
18 /*
19 * $Id: viewtablelock.cpp 2101 2013-01-21 14:12:52Z rdempsey $
20 */
21
22
23 #include <ctime>
24 #include <iostream>
25 #include <vector>
26 #include <stdexcept>
27 #include <sstream>
28 #include <string>
29
30 #include "calpontsystemcatalog.h"
31 #include "dbrm.h"
32 #include "exceptclasses.h"
33
34 using namespace execplan;
35
36 namespace
37 {
38
39 //------------------------------------------------------------------------------
40 // Print command line usage
41 //------------------------------------------------------------------------------
usage()42 void usage()
43 {
44 std::cout << "Usage: viewtablelock [schemaname tablename]" << std::endl
45 << " If schema/table are specified, then that table's lock " <<
46 "information is displayed." << std::endl
47 << " If no schema/table are specified, then all table locks "
48 "are displayed." << std::endl;
49 }
50
51 //------------------------------------------------------------------------------
52 // Print table locks.
53 // This function closely resembles CommandPackageProcessor::viewTableLock().
54 //------------------------------------------------------------------------------
printTableLocks(boost::shared_ptr<CalpontSystemCatalog> systemCatalogPtr,const std::string & tableNameIn,const std::vector<BRM::TableLockInfo> tableLocks)55 int printTableLocks( boost::shared_ptr<CalpontSystemCatalog> systemCatalogPtr,
56 const std::string& tableNameIn,
57 const std::vector<BRM::TableLockInfo> tableLocks )
58 {
59 if (tableLocks.size() == 1)
60 std::cout << " There is " << tableLocks.size() <<
61 " table lock" << std::endl << std::endl;
62 else
63 std::cout << " There are " << tableLocks.size() <<
64 " table locks" << std::endl << std::endl;
65
66 std::string tableName(tableNameIn);
67
68 // Make preliminary pass through the table locks in order to determine our
69 // output column widths based on the data. Min column widths are based on
70 // the width of the column heading (except for the 'state' column).
71 uint64_t maxLockID = 0;
72 uint32_t maxPID = 0;
73 int32_t maxSessionID = 0;
74 int32_t minSessionID = 0;
75 int32_t maxTxnID = 0;
76
77 unsigned int tableNameColumnWidth = 5; // "Table"
78 unsigned int lockIDColumnWidth = 6; // "LockID"
79 unsigned int ownerColumnWidth = 7; // "Process"
80 unsigned int pidColumnWidth = 3; // "PID"
81 unsigned int sessionIDColumnWidth = 7; // "Session"
82 unsigned int txnIDColumnWidth = 3; // "Txn"
83 unsigned int createTimeColumnWidth = 12; // "CreationTime"
84 unsigned int pmColumnWidth = 7; // "DBRoots"
85 std::vector<std::string> createTimes;
86 char cTimeBuffer[1024];
87 std::vector<std::string> tableNames;
88
89 std::ostringstream errMsgs;
90
91 for (unsigned int i = 0; i < tableLocks.size(); i++)
92 {
93 if (tableNameIn.empty())
94 {
95 try
96 {
97 CalpontSystemCatalog::TableName tableNameStruct;
98 tableNameStruct = systemCatalogPtr->tableName(
99 tableLocks[i].tableOID);
100 tableName = tableNameStruct.toString();
101 }
102 catch ( logging::IDBExcept&)
103 {
104 tableName.clear();
105
106 errMsgs << "Table with oid " << tableLocks[i].tableOID <<
107 " (Lock " << tableLocks[i].id << ")" <<
108 " is not in systable." << std::endl;
109 }
110 catch (std::runtime_error& e)
111 {
112 tableName.clear();
113
114 errMsgs <<
115 "Error searching for table " << tableLocks[i].tableOID <<
116 " (Lock " << tableLocks[i].id << ")" <<
117 " in system catalog. " << e.what() << std::endl;
118 }
119 catch (...)
120 {
121 tableName.clear();
122
123 errMsgs <<
124 "Unknown error searching for table " <<
125 tableLocks[i].tableOID <<
126 " (Lock " << tableLocks[i].id << ")" <<
127 " in system catalog. " << std::endl;
128 }
129 }
130
131 tableNames.push_back( tableName );
132
133 tableNameColumnWidth = std::max(tableNameColumnWidth,
134 static_cast<unsigned int>(tableName.length()));
135 maxLockID = std::max(maxLockID, tableLocks[i].id);
136 ownerColumnWidth = std::max(ownerColumnWidth,
137 static_cast<unsigned int>(tableLocks[i].ownerName.length()));
138 maxPID = std::max(maxPID, tableLocks[i].ownerPID);
139 maxSessionID = std::max(maxSessionID, tableLocks[i].ownerSessionID);
140 minSessionID = std::min(minSessionID, tableLocks[i].ownerSessionID);
141 maxTxnID = std::max(maxTxnID, tableLocks[i].ownerTxnID);
142
143 ctime_r( &tableLocks[i].creationTime, cTimeBuffer );
144 cTimeBuffer[ strlen(cTimeBuffer) - 1 ] = '\0'; // strip trailing '\n'
145 std::string cTimeStr( cTimeBuffer );
146 createTimeColumnWidth = std::max(createTimeColumnWidth,
147 static_cast<unsigned int>(cTimeStr.length()));
148 createTimes.push_back( cTimeStr );
149
150 std::ostringstream pms;
151
152 for (unsigned k = 0; k < tableLocks[i].dbrootList.size(); k++)
153 {
154 if (k > 0)
155 pms << ',';
156
157 pms << tableLocks[i].dbrootList[k];
158 }
159
160 pmColumnWidth = std::max(pmColumnWidth,
161 static_cast<unsigned int>(pms.str().length()));
162 }
163
164 tableNameColumnWidth += 2;
165 ownerColumnWidth += 2;
166 pmColumnWidth += 2;
167 createTimeColumnWidth += 2;
168
169 std::ostringstream idString;
170 idString << maxLockID;
171 lockIDColumnWidth = std::max(lockIDColumnWidth,
172 static_cast<unsigned int>(idString.str().length()));
173 lockIDColumnWidth += 2;
174
175 std::ostringstream pidString;
176 pidString << maxPID;
177 pidColumnWidth = std::max(pidColumnWidth,
178 static_cast<unsigned int>(pidString.str().length()));
179 pidColumnWidth += 2;
180
181 const std::string sessionNoneStr("BulkLoad");
182 std::ostringstream sessionString;
183 sessionString << maxSessionID;
184 sessionIDColumnWidth = std::max(sessionIDColumnWidth,
185 static_cast<unsigned int>(sessionString.str().length()));
186
187 if (minSessionID < 0)
188 sessionIDColumnWidth = std::max(sessionIDColumnWidth,
189 static_cast<unsigned int>(sessionNoneStr.length()));
190
191 sessionIDColumnWidth += 2;
192
193 const std::string txnNoneStr("n/a");
194 std::ostringstream txnString;
195 txnString << maxTxnID;
196 txnIDColumnWidth = std::max(txnIDColumnWidth,
197 static_cast<unsigned int>(txnString.str().length()));
198 txnIDColumnWidth += 2;
199
200 std::cout.setf(std::ios::left, std::ios::adjustfield);
201 std::cout << " " <<
202 std::setw(tableNameColumnWidth) << "Table" <<
203 std::setw(lockIDColumnWidth) << "LockID" <<
204 std::setw(ownerColumnWidth) << "Process" <<
205 std::setw(pidColumnWidth) << "PID" <<
206 std::setw(sessionIDColumnWidth) << "Session" <<
207 std::setw(txnIDColumnWidth) << "Txn" <<
208 std::setw(createTimeColumnWidth) << "CreationTime" <<
209 std::setw(9) << "State" <<
210 std::setw(pmColumnWidth) << "DBRoots" << std::endl;
211
212 // Make second pass through the table locks to display our result.
213 for (unsigned idx = 0; idx < tableLocks.size(); idx++)
214 {
215 std::ostringstream pms; //dbroots now
216
217 for (unsigned k = 0; k < tableLocks[idx].dbrootList.size(); k++)
218 {
219 if (k > 0)
220 pms << ',';
221
222 pms << tableLocks[idx].dbrootList[k];
223 }
224
225 std::cout << " " <<
226 std::setw(tableNameColumnWidth) << tableNames[idx] <<
227 std::setw(lockIDColumnWidth) << tableLocks[idx].id <<
228 std::setw(ownerColumnWidth) << tableLocks[idx].ownerName <<
229 std::setw(pidColumnWidth) << tableLocks[idx].ownerPID;
230
231 // Log session ID, or "BulkLoad" if session is -1
232 if (tableLocks[idx].ownerSessionID < 0)
233 std::cout << std::setw(sessionIDColumnWidth) << sessionNoneStr;
234 else
235 std::cout << std::setw(sessionIDColumnWidth) <<
236 tableLocks[idx].ownerSessionID;
237
238 // Log txn ID, or "n/a" if txn is -1
239 if (tableLocks[idx].ownerTxnID < 0)
240 std::cout << std::setw(txnIDColumnWidth) << txnNoneStr;
241 else
242 std::cout << std::setw(txnIDColumnWidth) <<
243 tableLocks[idx].ownerTxnID;
244
245 std::cout <<
246 std::setw(createTimeColumnWidth) <<
247 createTimes[idx] <<
248 std::setw(9) << ((tableLocks[idx].state == BRM::LOADING) ?
249 "LOADING" : "CLEANUP") <<
250 std::setw(pmColumnWidth) << pms.str() << std::endl;
251 }
252
253 if (!errMsgs.str().empty())
254 std::cerr << std::endl << errMsgs.str() << std::endl;
255
256 return 0;
257 }
258
259 }
260
261 //------------------------------------------------------------------------------
262 // Main entry point to this program
263 //------------------------------------------------------------------------------
main(int argc,char ** argv)264 int main(int argc, char** argv)
265 {
266 int c;
267
268 while ((c = getopt(argc, argv, "h")) != EOF)
269 {
270 switch (c)
271 {
272 case 'h':
273 case '?':
274 default:
275 usage();
276 return (c == 'h' ? 0 : 1);
277 break;
278 }
279 }
280
281 int nargs = argc - optind;
282
283 if ((nargs > 2) || (nargs == 1))
284 {
285 usage();
286 return 1;
287 }
288
289 BRM::DBRM dbrm;
290 std::vector<BRM::TableLockInfo> tableLocks;
291
292 try
293 {
294 tableLocks = dbrm.getAllTableLocks();
295 }
296 catch (std::exception& ex)
297 {
298 std::cerr << "Error getting list of table locks: " << ex.what() <<
299 std::endl;
300 return 2;
301 }
302
303 int rc = 0;
304
305 if (nargs == 2) // List table lock information for a given table
306 {
307 std::string schema(argv[optind++]);
308 std::string table( argv[optind++]);
309
310 // Get table oid
311 boost::shared_ptr<CalpontSystemCatalog> systemCatalogPtr =
312 CalpontSystemCatalog::makeCalpontSystemCatalog(1);
313 systemCatalogPtr->identity(CalpontSystemCatalog::EC);
314 CalpontSystemCatalog::TableName tableName;
315 tableName.schema = schema;
316 tableName.table = table;
317 CalpontSystemCatalog::ROPair roPair;
318
319 try
320 {
321 roPair = systemCatalogPtr->tableRID( tableName );
322 }
323 catch (logging::IDBExcept& e)
324 {
325 std::cerr << e.what() << std::endl;
326 return 3;
327 }
328 catch (std::runtime_error& e)
329 {
330 std::cerr << "Error searching for table in system catalog. " <<
331 e.what() << std::endl;
332 return 4;
333 }
334 catch (...)
335 {
336 std::cerr << "Unknown error searching for table in system catalog."
337 << std::endl;
338 return 5;
339 }
340
341 // Keep in mind the same table could have more than 1 lock
342 // (on different PMs), so we don't exit loop after "first" match.
343 std::vector<BRM::TableLockInfo> matchingTableLocks;
344
345 for (unsigned int i = 0; i < tableLocks.size(); i++)
346 {
347 if (roPair.objnum == (CalpontSystemCatalog::OID)
348 tableLocks[i].tableOID)
349 {
350 matchingTableLocks.push_back( tableLocks[i] );
351 }
352 }
353
354 if (matchingTableLocks.size() > 0)
355 {
356 std::string tableName(schema);
357 tableName += '.';
358 tableName += table;
359 rc = printTableLocks( systemCatalogPtr,
360 tableName, matchingTableLocks );
361 }
362 else
363 {
364 std::cout << " Table " << schema << "." << table <<
365 " is not locked by any process. " << std::endl;
366 }
367 }
368 else // List table lock information for all table locks
369 {
370 //All table lock info required
371 if (tableLocks.size() == 0)
372 {
373 std::cout << " No tables are locked in the database." << std::endl;
374 }
375 else
376 {
377 boost::shared_ptr<CalpontSystemCatalog> systemCatalogPtr =
378 CalpontSystemCatalog::makeCalpontSystemCatalog();
379 systemCatalogPtr->identity(CalpontSystemCatalog::EC);
380
381 std::string tableName;
382 rc = printTableLocks( systemCatalogPtr,
383 tableName, tableLocks );
384 }
385 }
386
387 return rc;
388 }
389