WL#3363: ndb$info

Status: Complete   —   Priority: Medium

We hear a lot of demand for "more monitoring" for NDB. Sometimes there's some
ideas about what people want, sometimes not. We aim for a generic interface that
makes it easy for NDB coders to add information and easy for users, support or
developers to access this information.

For the initial implementation, speed is not a priority.

Existing information:
- some statistics can be gotten from various DUMP numbers
- stored in variables inside ndbd or can be easily computed.

Proposed interface:
- table accessible from SQL so that users can just SELECT from it.
- Also simple interface from ndb_mgm to easily "query" ndb$info tables from
command line (basically a SELECT * FROM X without a where clause)

common HOWTO impl:
1) Data structure for (statically) specifying NDB$INFO tables (no need to
allocate memory)
2) code for generating CREATE TABLE statements from structure (run these in
mysqld to get FRM files)
3) global list of NDB$INFO tables for node

mgmd HOWTO impl:
1) new "ndbinfo" protocol command.
2) export some information from mgmd (would be good to query even if cluster not up)
    a) log destinations/status
    b) current session information (list sessions/show sessions)
    c) configuration information (all nodes should output this)

Kernel HOWTO impl:

1) Create new block Dbinfo
   Which has a simple scan like interface
   GSN_GET_INFO_REQ
   GSN_GET_NEXT_INFO_REQ

2) Create new ndbapi interface for scanning

3) Create ndb$tables

mysqld HOWTO impl:

4) Create new handler ndbinfo
   rnd_init
   rnd_next
   create

5) Create frm files for ndb$tables

----

key points:
1) new block + new signal interface + new ndbapi interface
2) new handler for accessing

Test plan (in development)
https://inside.mysql.com/wiki/ClusterNdbInfoTestPlan

----

SQL interface to NDB$INFO, take 2 By Martin

Subject:
SQL interface to NDB$INFO, take 2
From:
Martin Skold <Martin.Skold@sun.com>
Date:
Tue, 03 Feb 2009 09:41:54 +0100
To:
dev-ndb <dev-ndb@mysql.com>

A new version of the SQL interface to NDB$INFO has been committed.

http://lists.mysql.com/commits/64925

The actual tables in NDB$INFO have not been changed, this can now
be an open discussion on what they should contain.

Here is a summary of what it contains:

- An extension of the Ndb API with a new meta-data
  type NdbDictionary::InfoTable and a new operation
  NdbInfoScanOperation. Instead of using transactions
  a NdbInfoHandle is used to connect.

- A new pluggable storage engine, ha_ndbcluster_info,
  has been implemented that provides an SQL interface
  to NDB$INFO tables
  (using the new NdbInfoScan interface in the NdbAPI).

- The engine currently needs to be installed manually
  by the user (INSTALL PLUGIN). This will create the
  database NDB$INFO (if not already created).

Some improvements include:

- A utility script can be created by executing the
  program ndbinfo_bootstrap. This will load the plugin
  and create all the tables along with a utility table
  that maps BLOCK_NUMBER to BLOCK_NAME.

- In ha_ndbcluster_info::open a check has been added verifies
  that kernel definition of table and mysql table are compatible.
  (Iterates all fields and compares field types with what NDB$INFO
   assumes).

- Tables can be upgraded by dropping frm files and doing a
  show tables; command (or manually redefining them using output
  from newly built ndbinfo_bootstrap).

To build and run the new interface:
In storage/ha_ndbcluster_info/ :
make install
This will install the plugin in the directory:
<plugin dir>:=<data dir>/lib/mysql/plugin
A utility program is also created that outputs SQL commands:
ndbinfo_bootstrap

Start mysqld with the following flag:
--plugin_dir=<plugin dir>
Run the SQL commands from ndbinfo_bootstrap:
mysql> CREATE DATABASE IF NOT EXISTS NDB$INFO;
Query OK, 1 row affected (0.21 sec)

mysql> INSTALL PLUGIN ndbcluster_info SONAME 'ha_ndbcluster_info.so';
Query OK, 0 rows affected, 1 warning (0.01 sec)
...

The new tables can be found in database NDB$INFO:
mysql> use NDB$INFO;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+--------------------+
| Tables_in_NDB$INFO |
+--------------------+
| BACKUP_PARAMETERS  |
| BACKUP_RECORDS     |
| BLOCK_NAME         |
| COLUMNS            |
| LOGDESTINATION     |
| MEMUSAGE           |
| POOLS              |
| TABLES             |
+--------------------+
8 rows in set (0.14 sec)


mysql> select * from MEMUSAGE;
+---------------+---------+--------------+------------+-------------+--------------+
| RESOURCE_NAME | NODE_ID | PAGE_SIZE_KB | PAGES_USED | PAGES_TOTAL | BLOCK_NUMBER |
+---------------+---------+--------------+------------+-------------+--------------+
| IndexMemory   |       1 |            0 |         17 |         544 |        248 |
| DataMemory    |       1 |            0 |          6 |         640 |        249 |
| IndexMemory   |       2 |            0 |         17 |         544 |        248 |
| DataMemory    |       2 |            0 |          6 |         640 |        249 |
+---------------+---------+--------------+------------+-------------+--------------+
4 rows in set (0.02 sec)

mysql> select BLOCK_NAME, m.* from BLOCK_NAME b, MEMUSAGE m where b.BLOCK_NUMBER
= m.BLOCK_NUMBER;
+------------+---------------+---------+--------------+------------+-------------+--------------+
| BLOCK_NAME | RESOURCE_NAME | NODE_ID | PAGE_SIZE_KB | PAGES_USED | PAGES_TOTAL
| BLOCK_NUMBER |
+------------+---------------+---------+--------------+------------+-------------+--------------+
| DBACC      | IndexMemory   |       1 |            0 |         17 |      544 |
         248 |
| DBTUP      | DataMemory    |       1 |            0 |          6 |      640 |
         249 |
| DBACC      | IndexMemory   |       2 |            0 |         17 |      544 |
         248 |
| DBTUP      | DataMemory    |       2 |            0 |          6 |      640 |
         249 |
+------------+---------------+---------+--------------+------------+-------------+--------------+
4 rows in set (0.03 sec)

mysql> select * from POOLS;
+---------+--------+-------------------------+-------+------------+
| NODE_ID | BLOCK  | POOL_NAME               | FREE  | SIZE       |
+---------+--------+-------------------------+-------+------------+
|       1 | DBTUP  | Scan Lock               | 32832 |      32832 |
|       1 | DBTUP  | Scan Operation          |   513 |        514 |
|       1 | DBTUP  | Trigger                 |  1001 |       1010 |
|       1 | DBTUP  | Stored Proc             |   513 |        513 |
|       1 | DBTUP  | Build Index             |    32 |         32 |
|       1 | DBTUP  | Operation               |     0 |      11050 |
|       1 | DBTUP  | Page                    |     0 | 4294967295 |
|       1 | BACKUP | Backup Record           |     1 |          2 |
|       1 | BACKUP | Backup File             |     3 |          4 |
|       1 | BACKUP | Table                   |   323 |        323 |
|       1 | BACKUP | Trigger                 |   966 |        966 |
|       1 | BACKUP | Fragment                |  1289 |       1289 |
|       1 | BACKUP | Page                    |   137 |        201 |
|       1 | DBTC   | Defined Trigger         |  1010 |       1010 |
|       1 | DBTC   | Fired Trigger           |  4000 |       4000 |
|       1 | DBTC   | Index                   |   322 |        322 |
|       1 | DBTC   | Scan Fragment           |   513 |        513 |
|       1 | DBTC   | Commit ACK Marker       |     0 |          0 |
|       1 | DBTC   | Index Op                |     0 |          0 |
|       1 | SUMA   | Subscriber              |   254 |        260 |
|       1 | SUMA   | Table                   |   127 |        130 |
|       1 | SUMA   | Subscription            |   127 |        130 |
|       1 | SUMA   | Sync                    |     2 |          2 |
|       1 | SUMA   | Data Buffer             |  2057 |       2057 |
|       1 | SUMA   | SubOp                   |     0 |          0 |
|       1 | SUMA   | Page Chunk              |    49 |         50 |
|       1 | SUMA   | GCP                     |  1210 |       1210 |
|       1 | DBUTIL | Page                    |    10 |         10 |
|       1 | DBUTIL | Prepare                 |     1 |          1 |
|       1 | DBUTIL | Prepared Operation      |     2 |          6 |
|       1 | DBUTIL | Operation               |    64 |         64 |
|       1 | DBUTIL | Transaction             |    32 |         32 |
|       1 | DBUTIL | Attribute Mapping       |   100 |        100 |
|       1 | DBUTIL | Data Buffer             |  5997 |       6000 |
|       1 | TRIX   | Attribute Order Buffer  |   100 |        100 |
|       1 | TRIX   | Subscription Record     |   100 |        100 |
|       1 | DBTC   | Index                   |     0 |        322 |
|       1 | DBTC   | Fragment                |     0 |          0 |
|       1 | DBTC   | Descriptor page         |     6 |          6 |
|       1 | DBTC   | Fragment Operation      |     8 |          8 |
|       1 | DBTC   | Scan Operation          |   513 |        513 |
|       1 | DBTC   | Scan Bound              | 14364 |      14364 |
|       1 | DBTC   | Scan Lock               | 32832 |      32832 |
|       1 | DBDICT | Attribute Record        |  2028 |       2057 |
|       1 | DBDICT | Table Record            |     0 |        322 |
|       1 | DBDICT | Trigger Record          |     0 |       1010 |
|       1 | DBDICT | FS Connect Record       |     4 |          4 |
|       1 | DBDICT | DictObject              |  1326 |       1332 |
|       1 | DBDICT | Schema Operation        |     0 |          0 |
|       1 | DBDICT | Schema Transaction      |     5 |          5 |
|       1 | DBDICT | Transaction Handle      |     2 |          2 |
|       1 | DBDICT | Create Table Record     |    32 |         32 |
|       1 | DBDICT | Drop Table Record       |    32 |         32 |
|       1 | DBDICT | Alter Table Record      |    32 |         32 |
|       1 | DBDICT | Create Index Record     |    32 |         32 |
|       1 | DBDICT | Drop Index Record       |    32 |         32 |
|       1 | DBDICT | Alter Index Record      |    32 |         32 |
|       1 | DBDICT | Build Index Record      |    32 |         32 |
|       1 | DBDICT | Create Hash Map Record  |    32 |         32 |
|       1 | DBDICT | Copy Data Record        |    32 |         32 |
|       1 | DBDICT | Create Trigger Record   |    32 |         32 |
|       1 | DBDICT | Drop Trigger Record     |    32 |         32 |
|       1 | DBDICT | Create Filegroup Record |    32 |         32 |
|       1 | DBDICT | Create File Record      |    32 |         32 |
|       1 | DBDICT | Drop Filegroup Record   |    32 |         32 |
|       1 | DBDICT | Drop File Record        |    32 |         32 |
|       1 | DBDICT | Operation Record        |     0 |          0 |
|       2 | DBTUP  | Scan Lock               | 32832 |      32832 |
|       2 | DBTUP  | Scan Operation          |   513 |        514 |
|       2 | DBTUP  | Trigger                 |  1001 |       1010 |
|       2 | DBTUP  | Stored Proc             |   513 |        513 |
|       2 | DBTUP  | Build Index             |    32 |         32 |
|       2 | DBTUP  | Operation               |     0 |      11050 |
|       2 | DBTUP  | Page                    |     0 | 4294967295 |
|       2 | BACKUP | Backup Record           |     1 |          2 |
|       2 | BACKUP | Backup File             |     3 |          4 |
|       2 | BACKUP | Table                   |   323 |        323 |
|       2 | BACKUP | Trigger                 |   966 |        966 |
|       2 | BACKUP | Fragment                |  1289 |       1289 |
|       2 | BACKUP | Page                    |   137 |        201 |
|       2 | DBTC   | Defined Trigger         |  1010 |       1010 |
|       2 | DBTC   | Fired Trigger           |  4000 |       4000 |
|       2 | DBTC   | Index                   |   322 |        322 |
|       2 | DBTC   | Scan Fragment           |   513 |        513 |
|       2 | DBTC   | Commit ACK Marker       |     0 |          0 |
|       2 | DBTC   | Index Op                |     0 |          0 |
|       2 | SUMA   | Subscriber              |   254 |        260 |
|       2 | SUMA   | Table                   |   127 |        130 |
|       2 | SUMA   | Subscription            |   127 |        130 |
|       2 | SUMA   | Sync                    |     2 |          2 |
|       2 | SUMA   | Data Buffer             |  2057 |       2057 |
|       2 | SUMA   | SubOp                   |     0 |          0 |
|       2 | SUMA   | Page Chunk              |    49 |         50 |
|       2 | SUMA   | GCP                     |  1210 |       1210 |
|       2 | DBUTIL | Page                    |    10 |         10 |
|       2 | DBUTIL | Prepare                 |     1 |          1 |
|       2 | DBUTIL | Prepared Operation      |     2 |          6 |
|       2 | DBUTIL | Operation               |    64 |         64 |
|       2 | DBUTIL | Transaction             |    32 |         32 |
|       2 | DBUTIL | Attribute Mapping       |   100 |        100 |
|       2 | DBUTIL | Data Buffer             |  5997 |       6000 |
|       2 | TRIX   | Attribute Order Buffer  |   100 |        100 |
|       2 | TRIX   | Subscription Record     |   100 |        100 |
|       2 | DBTC   | Index                   |     0 |        322 |
|       2 | DBTC   | Fragment                |     0 |          0 |
|       2 | DBTC   | Descriptor page         |     6 |          6 |
|       2 | DBTC   | Fragment Operation      |     8 |          8 |
|       2 | DBTC   | Scan Operation          |   513 |        513 |
|       2 | DBTC   | Scan Bound              | 14364 |      14364 |
|       2 | DBTC   | Scan Lock               | 32832 |      32832 |
|       2 | DBDICT | Attribute Record        |  2028 |       2057 |
|       2 | DBDICT | Table Record            |     0 |        322 |
|       2 | DBDICT | Trigger Record          |     0 |       1010 |
|       2 | DBDICT | FS Connect Record       |     4 |          4 |
|       2 | DBDICT | DictObject              |  1326 |       1332 |
|       2 | DBDICT | Schema Operation        |     0 |          0 |
|       2 | DBDICT | Schema Transaction      |     5 |          5 |
|       2 | DBDICT | Transaction Handle      |     2 |          2 |
|       2 | DBDICT | Create Table Record     |    32 |         32 |
|       2 | DBDICT | Drop Table Record       |    32 |         32 |
|       2 | DBDICT | Alter Table Record      |    32 |         32 |
|       2 | DBDICT | Create Index Record     |    32 |         32 |
|       2 | DBDICT | Drop Index Record       |    32 |         32 |
|       2 | DBDICT | Alter Index Record      |    32 |         32 |
|       2 | DBDICT | Build Index Record      |    32 |         32 |
|       2 | DBDICT | Create Hash Map Record  |    32 |         32 |
|       2 | DBDICT | Copy Data Record        |    32 |         32 |
|       2 | DBDICT | Create Trigger Record   |    32 |         32 |
|       2 | DBDICT | Drop Trigger Record     |    32 |         32 |
|       2 | DBDICT | Create Filegroup Record |    32 |         32 |
|       2 | DBDICT | Create File Record      |    32 |         32 |
|       2 | DBDICT | Drop Filegroup Record   |    32 |         32 |
|       2 | DBDICT | Drop File Record        |    32 |         32 |
|       2 | DBDICT | Operation Record        |     0 |          0 |
+---------+--------+-------------------------+-------+------------+
134 rows in set (0.02 sec)

mysql> select * from TABLES;
+----------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TABLE_ID | TABLE_NAME        | CREATE_SQL





                                              |
+----------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|        0 | TABLES            | CREATE TABLE IF NOT EXISTS `NDB$INFO`.`TABLES` (
        `TABLE_ID` INT UNSIGNED,
        `TABLE_NAME` VARCHAR(512),
        `CREATE_SQL` VARCHAR(512)
) ENGINE=NDBCLUSTER_INFO;



                         |
|        1 | COLUMNS           | CREATE TABLE IF NOT EXISTS `NDB$INFO`.`COLUMNS` (
        `TABLE_ID` INT UNSIGNED,
        `COLUMN_ID` INT UNSIGNED,
        `COLUMN_NAME` VARCHAR(512),
        `COLUMN_TYPE` VARCHAR(512)
) ENGINE=NDBCLUSTER_INFO;


                                                                  |
|        2 | MEMUSAGE          | CREATE TABLE IF NOT EXISTS `NDB$INFO`.`MEMUSAGE` (
        `RESOURCE_NAME` VARCHAR(512),
        `NODE_ID` INT UNSIGNED,
        `PAGE_SIZE_KB` INT UNSIGNED,
        `PAGES_USED` INT UNSIGNED,
        `PAGES_TOTAL` INT UNSIGNED,
        `BLOCK_NUMBER` INT UNSIGNED
) ENGINE=NDBCLUSTER_INFO;


   |
|        3 | LOGDESTINATION    | CREATE TABLE IF NOT EXISTS
`NDB$INFO`.`LOGDESTINATION` (
        `NODE_ID` INT UNSIGNED,
        `TYPE` VARCHAR(512),
        `PARAMS` VARCHAR(512),
        `CURRENT_SIZE` INT UNSIGNED,
        `MAX_SIZE` INT UNSIGNED
) ENGINE=NDBCLUSTER_INFO;


                                           |
|        4 | BACKUP_RECORDS    | CREATE TABLE IF NOT EXISTS
`NDB$INFO`.`BACKUP_RECORDS` (
        `NODE_ID` INT UNSIGNED,
        `BACKUP_RECORD` INT UNSIGNED,
        `BACKUP_ID` INT UNSIGNED,
        `MASTER_REF` INT UNSIGNED,
        `CLIENT_REF` INT UNSIGNED,
        `STATE` INT UNSIGNED,
        `BYTES` INT UNSIGNED,
        `RECORDS` INT UNSIGNED,
        `LOG_BYTES` INT UNSIGNED,
        `LOG_RECORDS` INT UNSIGNED,
        `ERROR_CODE` INT UNSIGNED
) ENGINE=NDBCLUSTER_INFO;
                  |
|        5 | BACKUP_PARAMETERS | CREATE TABLE IF NOT EXISTS
`NDB$INFO`.`BACKUP_PARAMETERS` (
        `NODE_ID` INT UNSIGNED,
        `CURRENT_DISK_WRITE_SPEED` INT UNSIGNED,
        `BYTES_WRITTEN_THIS_PERIOD` INT UNSIGNED,
        `OVERFLOW_DISK_WRITE` INT UNSIGNED,
        `RESET_DELAY_USED` INT UNSIGNED,
        `RESET_DISK_SPEED_TIME` INT UNSIGNED,
        `BACKUP_POOL_SIZE` INT UNSIGNED,
        `BACKUP_FILE_POOL_SIZE` INT UNSIGNED,
        `TABLE_POOL_SIZE` INT UNSIGNED,
        `TRIGGER_POOL_SIZE` INT UNSIGNED,
        `FRAGMENT_POOL_SIZE` INT UNSIGNED,
        `PAGE_POOL_SIZE` INT UNSIGNED,
        `COMPRESSED_BACKUP`  |
|        6 | POOLS             | CREATE TABLE IF NOT EXISTS `NDB$INFO`.`POOLS` (
        `NODE_ID` INT UNSIGNED,
        `BLOCK` VARCHAR(512),
        `POOL_NAME` VARCHAR(512),
        `FREE` INT UNSIGNED,
        `SIZE` INT UNSIGNED
) ENGINE=NDBCLUSTER_INFO;


                                                            |
+----------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
7 rows in set (0.06 sec)

mysql> SELECT * FROM COLUMNS;
+----------+-----------+---------------------------+--------------+
| TABLE_ID | COLUMN_ID | COLUMN_NAME               | COLUMN_TYPE  |
+----------+-----------+---------------------------+--------------+
|        0 |         0 | TABLE_ID                  | INT UNSIGNED |
|        0 |         1 | TABLE_NAME                | VARCHAR(512) |
|        0 |         2 | CREATE_SQL                | VARCHAR(512) |
|        1 |         0 | TABLE_ID                  | INT UNSIGNED |
|        1 |         1 | COLUMN_ID                 | INT UNSIGNED |
|        1 |         2 | COLUMN_NAME               | VARCHAR(512) |
|        1 |         3 | COLUMN_TYPE               | VARCHAR(512) |
|        2 |         0 | RESOURCE_NAME             | VARCHAR(512) |
|        2 |         1 | NODE_ID                   | INT UNSIGNED |
|        2 |         2 | PAGE_SIZE_KB              | INT UNSIGNED |
|        2 |         3 | PAGES_USED                | INT UNSIGNED |
|        2 |         4 | PAGES_TOTAL               | INT UNSIGNED |
|        2 |         5 | BLOCK_NUMBER              | INT UNSIGNED |
|        3 |         0 | NODE_ID                   | INT UNSIGNED |
|        3 |         1 | TYPE                      | VARCHAR(512) |
|        3 |         2 | PARAMS                    | VARCHAR(512) |
|        3 |         3 | CURRENT_SIZE              | INT UNSIGNED |
|        3 |         4 | MAX_SIZE                  | INT UNSIGNED |
|        4 |         0 | NODE_ID                   | INT UNSIGNED |
|        4 |         1 | BACKUP_RECORD             | INT UNSIGNED |
|        4 |         2 | BACKUP_ID                 | INT UNSIGNED |
|        4 |         3 | MASTER_REF                | INT UNSIGNED |
|        4 |         4 | CLIENT_REF                | INT UNSIGNED |
|        4 |         5 | STATE                     | INT UNSIGNED |
|        4 |         6 | BYTES                     | INT UNSIGNED |
|        4 |         7 | RECORDS                   | INT UNSIGNED |
|        4 |         8 | LOG_BYTES                 | INT UNSIGNED |
|        4 |         9 | LOG_RECORDS               | INT UNSIGNED |
|        4 |        10 | ERROR_CODE                | INT UNSIGNED |
|        5 |         0 | NODE_ID                   | INT UNSIGNED |
|        5 |         1 | CURRENT_DISK_WRITE_SPEED  | INT UNSIGNED |
|        5 |         2 | BYTES_WRITTEN_THIS_PERIOD | INT UNSIGNED |
|        5 |         3 | OVERFLOW_DISK_WRITE       | INT UNSIGNED |
|        5 |         4 | RESET_DELAY_USED          | INT UNSIGNED |
|        5 |         5 | RESET_DISK_SPEED_TIME     | INT UNSIGNED |
|        5 |         6 | BACKUP_POOL_SIZE          | INT UNSIGNED |
|        5 |         7 | BACKUP_FILE_POOL_SIZE     | INT UNSIGNED |
|        5 |         8 | TABLE_POOL_SIZE           | INT UNSIGNED |
|        5 |         9 | TRIGGER_POOL_SIZE         | INT UNSIGNED |
|        5 |        10 | FRAGMENT_POOL_SIZE        | INT UNSIGNED |
|        5 |        11 | PAGE_POOL_SIZE            | INT UNSIGNED |
|        5 |        12 | COMPRESSED_BACKUP         | INT UNSIGNED |
|        5 |        13 | COMPRESSED_LCP            | INT UNSIGNED |
|        6 |         0 | NODE_ID                   | INT UNSIGNED |
|        6 |         1 | BLOCK                     | VARCHAR(512) |
|        6 |         2 | POOL_NAME                 | VARCHAR(512) |
|        6 |         3 | FREE                      | INT UNSIGNED |
|        6 |         4 | SIZE                      | INT UNSIGNED |
+----------+-----------+---------------------------+--------------+
48 rows in set (0.57 sec)

mysql>

Example: NDB$INFO_RESOURCES

CREATE TABLE NDB$INFO_RESOURCES (
       RESOURCE_NAME VARCHAR(50),
       RESOURCE_ID   INT,
       NODE_ID	     INT,
       RESOURCE_USED INT,
       RESOURCE_MAX  INT,
       PRIMARY KEY (RESOURCE_ID,NODE_ID)
);

mysql> select * FROM NDB$INFO_RESOURCES;
+----------------+-------------+---------+---------------+--------------+
| RESOURCE_NAME  | RESOURCE_ID | NODE_ID | RESOURCE_USED | RESOURCE_MAX |
+----------------+-------------+---------+---------------+--------------+
| NoOfTables     |         102 |       1 |            20 |          100 |
| NoOfTables     |         102 |       2 |            20 |          100 |
| NoOfAttributes |         103 |       1 |           200 |          512 |
| NoOfAttributes |         103 |       2 |           200 |          512 |
+----------------+-------------+---------+---------------+--------------+
4 rows in set (0.00 sec)


For example, upgrading DataMemory where node 2 has been restarted to have
more data memory but node 1 hasn't:

mysql> select * FROM NDB$INFO_RESOURCES WHERE RESOURCE_NAME='DataMemory';
+---------------+-------------+---------+---------------+--------------+
| RESOURCE_NAME | RESOURCE_ID | NODE_ID | RESOURCE_USED | RESOURCE_MAX |
+---------------+-------------+---------+---------------+--------------+
| DataMemory    |         112 |       1 |           100 |          288 |
| DataMemory    |         112 |       2 |           100 |          512 |
+---------------+-------------+---------+---------------+--------------+
2 rows in set (0.05 sec)
Common
------
Specifying a NDB$INFO table:

Want to be able to do something easy like:
DECLARE_NDBINFO_TABLE(t1,4) = {{"t1",4,0},
                               {
                                 {"col1",NDBINFO_TYPE_STRING},
                                 {"col2",NDBINFO_TYPE_STRING},
                                 {"col3",NDBINFO_TYPE_STRING},
                                 {"col4",NDBINFO_TYPE_STRING}
                               }};
for t1 being:
CREATE TABLE `t1` (
        `col1` VARCHAR(255),
        `col2` VARCHAR(255),
        `col3` VARCHAR(255),
        `col4` VARCHAR(255)
) ENGINE=NDBINFO;

(we replace STRING with something the SQL server currently understands... with
the cunning plan of introducing STRING at some point).

DBINFO Block
------------
"Manages" everything. Implements some infrastructure. Individual blocks
implement their own tables.

Getting table list:

   scan special table (id=0). This table has a list of tables.

Getting column list:
   scan special table (id=1). This table has list of all columns.
   (In scan interface we could optimise with start/stop block/item id to only
get column info on one table)

Scanning NDB$INFO Tables:

NDBINFO_SCANREQ
        tableId  // DBINFO table ID
	startBlockId    // Normally these 4 set to 0 by API
	startItemId     // but can be used as rather primitive
        stopBlockId     // pushed down conditions. e.g. to only get
        stopItemId      // columns of one NDB$INFO TABLE
        apiNodeId    // API doing scan
        apiTxnId     // ID unique to API. 
        column bitmap // bitmap of what columns you want. (64bit)

execNDBINFO_SCANCONF
	blockId   // to be sent in next NDBINFO_SCANREQ
        itemId    // as above

When complete, blockid=0xFFFFFFFF (done).
	If blockId!=0xFFFFFFFF, API needs to send DBINFO_SCANREQ again
	with blockid and item ID we sent them in DBINFO_SCANCONF

BLOCKS Implementing NDB$INFO tables
-----------------------------------

receive NDBINFO_SCANREQ (from DBINFO), send NDBINFO_SCANCONF (to DBINFO) on
completion of scanning some part of the table. sends TRANSID_AI directly to API
for each row.