/* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include void desc_AutoGrowSpecification(struct NdbDictionary::AutoGrowSpecification ags); int desc_logfilegroup(Ndb *myndb, char* name); int desc_undofile(Ndb_cluster_connection &con, Ndb *myndb, char* name); int desc_datafile(Ndb_cluster_connection &con, Ndb *myndb, char* name); int desc_tablespace(Ndb *myndb,char* name); int desc_index(Ndb *myndb, char* name); int desc_table(Ndb *myndb,char* name); int desc_hashmap(Ndb_cluster_connection &con, Ndb *myndb, char* name); static const char* _dbname = "TEST_DB"; static const char* _tblname = NULL; static int _unqualified = 0; static int _partinfo = 0; static int _blobinfo = 0; static int _nodeinfo = 0; const char *load_default_groups[]= { "mysql_cluster",0 }; static int _retries = 0; static struct my_option my_long_options[] = { NDB_STD_OPTS("ndb_desc"), { "database", 'd', "Name of database table is in", (uchar**) &_dbname, (uchar**) &_dbname, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "unqualified", 'u', "Use unqualified table names", (uchar**) &_unqualified, (uchar**) &_unqualified, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { "extra-partition-info", 'p', "Print more info per partition", (uchar**) &_partinfo, (uchar**) &_partinfo, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { "retries", 'r', "Retry every second for # retries", (uchar**) &_retries, (uchar**) &_retries, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "blob-info", 'b', "Show information for hidden blob tables (requires -p)", (uchar**) &_blobinfo, (uchar**) &_blobinfo, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { "extra-node-info", 'n', "Print node info for partitions (requires -p)", (uchar**) &_nodeinfo, (uchar**) &_nodeinfo, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { "table", 't', "Base table for index", (uchar**) &_tblname, (uchar**) &_tblname, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; static void short_usage_sub(void) { ndb_short_usage_sub(NULL); } static void usage() { ndb_usage(short_usage_sub, load_default_groups, my_long_options); } static void print_part_info(Ndb* pNdb, NdbDictionary::Table const* pTab); int main(int argc, char** argv){ NDB_INIT(argv[0]); ndb_opt_set_usage_funcs(short_usage_sub, usage); ndb_load_defaults(NULL,load_default_groups,&argc,&argv); int ho_error; #ifndef DBUG_OFF opt_debug= "d:t:O,/tmp/ndb_desc.trace"; #endif if ((ho_error=handle_options(&argc, &argv, my_long_options, ndb_std_get_one_option))) return NDBT_ProgramExit(NDBT_WRONGARGS); Ndb_cluster_connection con(opt_ndb_connectstring, opt_ndb_nodeid); con.set_name("ndb_desc"); if(con.connect(12, 5, 1) != 0) { ndbout << "Unable to connect to management server." << endl; return NDBT_ProgramExit(NDBT_FAILED); } if (con.wait_until_ready(30,0) < 0) { ndbout << "Cluster nodes not ready in 30 seconds." << endl; return NDBT_ProgramExit(NDBT_FAILED); } Ndb MyNdb(&con, _dbname); if(MyNdb.init() != 0){ NDB_ERR(MyNdb.getNdbError()); return NDBT_ProgramExit(NDBT_FAILED); } for(int i= 0; igetDictionary(); require(dict); NdbDictionary::LogfileGroup lfg= dict->getLogfileGroup(name); NdbError err= dict->getNdbError(); if( (int) err.classification != (int) ndberror_cl_none) return 0; ndbout << "Type: LogfileGroup" << endl; ndbout << "Name: " << lfg.getName() << endl; ndbout << "UndoBuffer size: " << lfg.getUndoBufferSize() << endl; ndbout << "Version: " << lfg.getObjectVersion() << endl; ndbout << "Free Words: " << lfg.getUndoFreeWords() << endl; desc_AutoGrowSpecification(lfg.getAutoGrowSpecification()); ndbout << endl; return 1; } int desc_tablespace(Ndb *myndb, char* name) { NdbDictionary::Dictionary *dict= myndb->getDictionary(); require(dict); NdbDictionary::Tablespace ts= dict->getTablespace(name); NdbError err= dict->getNdbError(); if ((int) err.classification != (int) ndberror_cl_none) return 0; ndbout << "Type: Tablespace" << endl; ndbout << "Name: " << ts.getName() << endl; ndbout << "Object Version: " << ts.getObjectVersion() << endl; ndbout << "Extent Size: " << ts.getExtentSize() << endl; ndbout << "Default Logfile Group: " << ts.getDefaultLogfileGroup() << endl; ndbout << endl; return 1; } int desc_undofile(Ndb_cluster_connection &con, Ndb *myndb, char* name) { unsigned id; NdbDictionary::Dictionary *dict= myndb->getDictionary(); Ndb_cluster_connection_node_iter iter; require(dict); con.init_get_next_node(iter); while ((id= con.get_next_node(iter))) { NdbDictionary::Undofile uf= dict->getUndofile(0, name); NdbError err= dict->getNdbError(); if ((int) err.classification != (int) ndberror_cl_none) return 0; ndbout << "Type: Undofile" << endl; ndbout << "Name: " << name << endl; ndbout << "Node: " << id << endl; ndbout << "Path: " << uf.getPath() << endl; ndbout << "Size: " << uf.getSize() << endl; ndbout << "Logfile Group: " << uf.getLogfileGroup() << endl; /** FIXME: are these needed, the functions aren't there but the prototypes are... ndbout << "Number: " << uf.getFileNo() << endl; */ ndbout << endl; } return 1; } int desc_datafile(Ndb_cluster_connection &con, Ndb *myndb, char* name) { unsigned id; NdbDictionary::Dictionary *dict= myndb->getDictionary(); require(dict); Ndb_cluster_connection_node_iter iter; con.init_get_next_node(iter); while ((id= con.get_next_node(iter))) { NdbDictionary::Datafile df= dict->getDatafile(id, name); NdbError err= dict->getNdbError(); if ((int) err.classification != (int) ndberror_cl_none) return 0; ndbout << "Type: Datafile" << endl; ndbout << "Name: " << name << endl; ndbout << "Node: " << id << endl; ndbout << "Path: " << df.getPath() << endl; ndbout << "Size: " << df.getSize() << endl; ndbout << "Free: " << df.getFree() << endl; ndbout << "Tablespace: " << df.getTablespace() << endl; /** We probably don't need to display this ever... ndbout << "Number: " << uf.getFileNo() << endl; */ ndbout << endl; } return 1; } int desc_index(Ndb *myndb, char* name) { NdbDictionary::Dictionary * dict= myndb->getDictionary(); NdbDictionary::Index const* pIndex; /* need to know base table */ if (_tblname == NULL) return 0; while ((pIndex = dict->getIndex(name, _tblname)) == NULL && --_retries >= 0) NdbSleep_SecSleep(1); if (pIndex == NULL) return 0; ndbout << "-- " << pIndex->getName() << " --" << endl; dict->print(ndbout, *pIndex); return 1; } int desc_table(Ndb *myndb, char* name) { NdbDictionary::Dictionary * dict= myndb->getDictionary(); NdbDictionary::Table const* pTab; while ((pTab = dict->getTable(name)) == NULL && --_retries >= 0) NdbSleep_SecSleep(1); if (!pTab) return 0; ndbout << "-- " << pTab->getName() << " --" << endl; dict->print(ndbout, *pTab); if (_partinfo) { print_part_info(myndb, pTab); ndbout << endl; if (_blobinfo) { int noOfAttributes = pTab->getNoOfColumns(); for (int i = 0; i < noOfAttributes; i++) { const NdbDictionary::Column* column = pTab->getColumn(i); if ((column->getType() == NdbDictionary::Column::Blob) || (column->getType() == NdbDictionary::Column::Text)) { print_part_info(myndb, (NDBT_Table*) column->getBlobTable()); ndbout << endl; } } } } return 1; } struct InfoInfo { const char * m_title; NdbRecAttr* m_rec_attr; const NdbDictionary::Column* m_column; }; static void print_part_info(Ndb* pNdb, NdbDictionary::Table const* pTab) { InfoInfo g_part_info[] = { { "Partition", 0, NdbDictionary::Column::FRAGMENT }, { "Row count", 0, NdbDictionary::Column::ROW_COUNT }, { "Commit count", 0, NdbDictionary::Column::COMMIT_COUNT }, { "Frag fixed memory", 0, NdbDictionary::Column::FRAGMENT_FIXED_MEMORY }, { "Frag varsized memory", 0, NdbDictionary::Column::FRAGMENT_VARSIZED_MEMORY }, { "Extent_space", 0, NdbDictionary::Column::FRAGMENT_EXTENT_SPACE }, { "Free extent_space", 0, NdbDictionary::Column::FRAGMENT_FREE_EXTENT_SPACE }, { 0, 0, 0 } }; const Uint32 FragmentIdOffset = 0; ndbout << "-- Per partition info"; if (_blobinfo && _partinfo) ndbout << " for " << pTab->getName(); ndbout << " -- " << endl; const Uint32 codeWords= 1; Uint32 codeSpace[ codeWords ]; NdbInterpretedCode code(NULL, // Table is irrelevant &codeSpace[0], codeWords); if ((code.interpret_exit_last_row() != 0) || (code.finalise() != 0)) { return; } NdbConnection* pTrans = pNdb->startTransaction(); if (pTrans == 0) return; do { NdbScanOperation* pOp= pTrans->getNdbScanOperation(pTab->getName()); if (pOp == NULL) break; int rs = pOp->readTuples(NdbOperation::LM_CommittedRead); if (rs != 0) break; if (pOp->setInterpretedCode(&code) != 0) break; Uint32 i = 0; for(i = 0; g_part_info[i].m_title != 0; i++) { if ((g_part_info[i].m_rec_attr = pOp->getValue(g_part_info[i].m_column)) == 0) break; } if (g_part_info[i].m_title != 0) break; if (pTrans->execute(NoCommit) != 0) break; for (i = 0; g_part_info[i].m_title != 0; i++) ndbout << g_part_info[i].m_title << "\t"; if (_nodeinfo) { ndbout << "Nodes\t"; } ndbout << endl; while(pOp->nextResult() == 0) { for(i = 0; g_part_info[i].m_title != 0; i++) { NdbRecAttr &r= *g_part_info[i].m_rec_attr; unsigned long long val; switch (r.getType()) { case NdbDictionary::Column::Bigunsigned: val= r.u_64_value(); break; case NdbDictionary::Column::Unsigned: val= r.u_32_value(); break; default: abort(); } if (val != 0) printf("%-*.llu\t", (int)strlen(g_part_info[i].m_title), val); else printf("0%*.s\t", (int)strlen(g_part_info[i].m_title), ""); } if (_nodeinfo) { Uint32 partId = g_part_info[ FragmentIdOffset ].m_rec_attr -> u_32_value(); const Uint32 MaxReplicas = 4; Uint32 nodeIds[ MaxReplicas ]; Uint32 nodeCnt = pTab->getFragmentNodes(partId, &nodeIds[0], MaxReplicas); if (nodeCnt) { for (Uint32 n = 0; n < nodeCnt; n++) { if (n > 0) printf(","); printf("%u", nodeIds[n]); } printf("\t"); } else { printf("-\t"); } } printf("\n"); } } while(0); pTrans->close(); } int desc_hashmap(Ndb_cluster_connection &con, Ndb *myndb, char* name) { NdbDictionary::Dictionary *dict= myndb->getDictionary(); require(dict); NdbDictionary::HashMap hm; if (dict->getHashMap(hm, name) == 0) { Uint32 len = hm.getMapLen(); Uint32 * tmp = new Uint32[len]; hm.getMapValues(tmp, len); for (Uint32 i = 0; i