List:Internals« Previous MessageNext Message »
From:jonas Date:October 10 2005 7:27pm
Subject:bk commit into 5.1 tree (jonas:1.1922)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of jonas. When jonas does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.1922 05/10/10 21:27:33 jonas@eel.(none) +236 -0
  Wl1870 - ndb diskdata
    Import into 5.1

  storage/ndb/src/kernel/vm/Rope.hpp
    1.1 05/10/10 21:27:23 jonas@eel.(none) +117 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/Rope.cpp
    1.1 05/10/10 21:27:23 jonas@eel.(none) +173 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/KeyTable2Ref.hpp
    1.1 05/10/10 21:27:23 jonas@eel.(none) +51 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/DLCHashTable.hpp
    1.1 05/10/10 21:27:23 jonas@eel.(none) +82 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/Rope.hpp
    1.0 05/10/10 21:27:23 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/vm/Rope.hpp

  storage/ndb/src/kernel/vm/Rope.cpp
    1.0 05/10/10 21:27:23 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/vm/Rope.cpp

  storage/ndb/src/kernel/vm/KeyTable2Ref.hpp
    1.0 05/10/10 21:27:23 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/vm/KeyTable2Ref.hpp

  storage/ndb/src/kernel/vm/DLCHashTable.hpp
    1.0 05/10/10 21:27:23 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/vm/DLCHashTable.hpp

  storage/ndb/src/kernel/vm/DLCFifoList.hpp
    1.1 05/10/10 21:27:22 jonas@eel.(none) +119 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/tsman.hpp
    1.1 05/10/10 21:27:22 jonas@eel.(none) +372 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/tsman.cpp
    1.1 05/10/10 21:27:22 jonas@eel.(none) +2101 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/restore.hpp
    1.1 05/10/10 21:27:22 jonas@eel.(none) +154 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/DLCFifoList.hpp
    1.0 05/10/10 21:27:22 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/vm/DLCFifoList.hpp

  storage/ndb/src/kernel/blocks/tsman.hpp
    1.0 05/10/10 21:27:22 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/tsman.hpp

  storage/ndb/src/kernel/blocks/tsman.cpp
    1.0 05/10/10 21:27:22 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/tsman.cpp

  storage/ndb/src/kernel/blocks/restore.hpp
    1.0 05/10/10 21:27:22 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/restore.hpp

  storage/ndb/src/kernel/blocks/restore.cpp
    1.1 05/10/10 21:27:21 jonas@eel.(none) +1211 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/print_file.cpp
    1.1 05/10/10 21:27:21 jonas@eel.(none) +370 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/pgman.hpp
    1.1 05/10/10 21:27:21 jonas@eel.(none) +459 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/pgman.cpp
    1.1 05/10/10 21:27:21 jonas@eel.(none) +1426 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/restore.cpp
    1.0 05/10/10 21:27:21 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/restore.cpp

  storage/ndb/src/kernel/blocks/print_file.cpp
    1.0 05/10/10 21:27:21 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/print_file.cpp

  storage/ndb/src/kernel/blocks/pgman.hpp
    1.0 05/10/10 21:27:21 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/pgman.hpp

  storage/ndb/src/kernel/blocks/pgman.cpp
    1.0 05/10/10 21:27:21 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/pgman.cpp

  storage/ndb/src/kernel/blocks/lgman.hpp
    1.1 05/10/10 21:27:20 jonas@eel.(none) +342 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/lgman.cpp
    1.1 05/10/10 21:27:20 jonas@eel.(none) +2952 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/diskpage.hpp
    1.1 05/10/10 21:27:20 jonas@eel.(none) +236 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/diskpage.cpp
    1.1 05/10/10 21:27:20 jonas@eel.(none) +75 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/tuppage.hpp
    1.1 05/10/10 21:27:20 jonas@eel.(none) +231 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/lgman.hpp
    1.0 05/10/10 21:27:20 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/lgman.hpp

  storage/ndb/src/kernel/blocks/lgman.cpp
    1.0 05/10/10 21:27:20 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/lgman.cpp

  storage/ndb/src/kernel/blocks/diskpage.hpp
    1.0 05/10/10 21:27:20 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/diskpage.hpp

  storage/ndb/src/kernel/blocks/diskpage.cpp
    1.0 05/10/10 21:27:20 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/diskpage.cpp

  storage/ndb/src/kernel/blocks/dbtup/tuppage.hpp
    1.0 05/10/10 21:27:20 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/dbtup/tuppage.hpp

  storage/ndb/src/kernel/blocks/dbtup/tuppage.cpp
    1.1 05/10/10 21:27:19 jonas@eel.(none) +330 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/test_varpage.cpp
    1.1 05/10/10 21:27:19 jonas@eel.(none) +125 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.hpp
    1.1 05/10/10 21:27:19 jonas@eel.(none) +57 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.cpp
    1.1 05/10/10 21:27:19 jonas@eel.(none) +120 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/tuppage.cpp
    1.0 05/10/10 21:27:19 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/dbtup/tuppage.cpp

  storage/ndb/src/kernel/blocks/dbtup/test_varpage.cpp
    1.0 05/10/10 21:27:19 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/dbtup/test_varpage.cpp

  storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.hpp
    1.0 05/10/10 21:27:19 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.hpp

  storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.cpp
    1.0 05/10/10 21:27:19 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.cpp

  storage/ndb/src/kernel/blocks/dbtup/DbtupVarAlloc.cpp
    1.1 05/10/10 21:27:18 jonas@eel.(none) +846 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp
    1.1 05/10/10 21:27:18 jonas@eel.(none) +1514 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbdih/printSysfile.cpp
    1.1 05/10/10 21:27:18 jonas@eel.(none) +160 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/TsmanContinueB.hpp
    1.1 05/10/10 21:27:18 jonas@eel.(none) +37 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupVarAlloc.cpp
    1.0 05/10/10 21:27:18 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/dbtup/DbtupVarAlloc.cpp

  storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp
    1.0 05/10/10 21:27:18 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp

  storage/ndb/src/kernel/blocks/dbdih/printSysfile.cpp
    1.0 05/10/10 21:27:18 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/dbdih/printSysfile.cpp

  storage/ndb/include/kernel/signaldata/TsmanContinueB.hpp
    1.0 05/10/10 21:27:18 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/TsmanContinueB.hpp

  storage/ndb/include/kernel/signaldata/RestoreImpl.hpp
    1.1 05/10/10 21:27:17 jonas@eel.(none) +66 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/RestoreContinueB.hpp
    1.1 05/10/10 21:27:17 jonas@eel.(none) +38 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/PgmanContinueB.hpp
    1.1 05/10/10 21:27:17 jonas@eel.(none) +34 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/LgmanContinueB.hpp
    1.1 05/10/10 21:27:17 jonas@eel.(none) +39 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/RestoreImpl.hpp
    1.0 05/10/10 21:27:17 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/RestoreImpl.hpp

  storage/ndb/include/kernel/signaldata/RestoreContinueB.hpp
    1.0 05/10/10 21:27:17 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/RestoreContinueB.hpp

  storage/ndb/include/kernel/signaldata/PgmanContinueB.hpp
    1.0 05/10/10 21:27:17 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/PgmanContinueB.hpp

  storage/ndb/include/kernel/signaldata/LgmanContinueB.hpp
    1.0 05/10/10 21:27:17 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/LgmanContinueB.hpp

  storage/ndb/include/kernel/signaldata/Extent.hpp
    1.1 05/10/10 21:27:16 jonas@eel.(none) +119 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/DropObj.hpp
    1.1 05/10/10 21:27:16 jonas@eel.(none) +118 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/DropFilegroupImpl.hpp
    1.1 05/10/10 21:27:16 jonas@eel.(none) +171 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/DropFilegroup.hpp
    1.1 05/10/10 21:27:16 jonas@eel.(none) +191 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/Extent.hpp
    1.0 05/10/10 21:27:16 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/Extent.hpp

  storage/ndb/include/kernel/signaldata/DropObj.hpp
    1.0 05/10/10 21:27:16 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/DropObj.hpp

  storage/ndb/include/kernel/signaldata/DropFilegroupImpl.hpp
    1.0 05/10/10 21:27:16 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/DropFilegroupImpl.hpp

  storage/ndb/include/kernel/signaldata/DropFilegroup.hpp
    1.0 05/10/10 21:27:16 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/DropFilegroup.hpp

  storage/ndb/include/kernel/signaldata/DictObjOp.hpp
    1.1 05/10/10 21:27:15 jonas@eel.(none) +104 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/CreateObj.hpp
    1.1 05/10/10 21:27:15 jonas@eel.(none) +107 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp
    1.1 05/10/10 21:27:15 jonas@eel.(none) +193 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/CreateFilegroup.hpp
    1.1 05/10/10 21:27:15 jonas@eel.(none) +198 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/DictObjOp.hpp
    1.0 05/10/10 21:27:15 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/DictObjOp.hpp

  storage/ndb/include/kernel/signaldata/CreateObj.hpp
    1.0 05/10/10 21:27:15 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/CreateObj.hpp

  storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp
    1.0 05/10/10 21:27:15 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp

  storage/ndb/include/kernel/signaldata/CreateFilegroup.hpp
    1.0 05/10/10 21:27:15 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/CreateFilegroup.hpp

  sql/sql_tablespace.cc
    1.1 05/10/10 21:27:14 jonas@eel.(none) +52 -0
    Wl1870 - ndb diskdata

  mysql-test/t/ndb_basic_disk.test
    1.1 05/10/10 21:27:14 jonas@eel.(none) +274 -0
    Wl1870 - ndb diskdata

  mysql-test/r/ndb_basic_disk.result
    1.1 05/10/10 21:27:14 jonas@eel.(none) +351 -0
    Wl1870 - ndb diskdata

  sql/sql_tablespace.cc
    1.0 05/10/10 21:27:14 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/sql/sql_tablespace.cc

  mysql-test/t/ndb_basic_disk.test
    1.0 05/10/10 21:27:14 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/mysql-test/t/ndb_basic_disk.test

  mysql-test/r/ndb_basic_disk.result
    1.0 05/10/10 21:27:14 jonas@eel.(none) +0 -0
    BitKeeper file /home/jonas/src/51-clean/mysql-test/r/ndb_basic_disk.result

  storage/ndb/tools/select_all.cpp
    1.24 05/10/10 20:32:31 jonas@eel.(none)[jonas] +47 -13
    Wl1870 - ndb diskdata

  storage/ndb/tools/restore/consumer_restore.cpp
    1.21 05/10/10 20:32:31 jonas@eel.(none)[jonas] +3 -3
    Wl1870 - ndb diskdata

  storage/ndb/tools/restore/Restore.cpp
    1.30 05/10/10 20:32:31 jonas@eel.(none)[jonas] +41 -19
    Wl1870 - ndb diskdata

  storage/ndb/tools/listTables.cpp
    1.24 05/10/10 20:32:31 jonas@eel.(none)[jonas] +13 -1
    Wl1870 - ndb diskdata

  storage/ndb/tools/desc.cpp
    1.21 05/10/10 20:32:31 jonas@eel.(none)[jonas] +171 -39
    Wl1870 - ndb diskdata

  storage/ndb/test/tools/hugoScanUpdate.cpp
    1.10 05/10/10 20:32:23 jonas@eel.(none)[jonas] +9 -7
    Wl1870 - ndb diskdata

  storage/ndb/test/tools/hugoPkReadRecord.cpp
    1.9 05/10/10 20:32:23 jonas@eel.(none)[jonas] +1 -54
    Wl1870 - ndb diskdata

  storage/ndb/test/tools/hugoLoad.cpp
    1.7 05/10/10 20:32:23 jonas@eel.(none)[jonas] +30 -14
    Wl1870 - ndb diskdata

  storage/ndb/test/src/UtilTransactions.cpp
    1.23 05/10/10 20:32:23 jonas@eel.(none)[jonas] +6 -9
    Wl1870 - ndb diskdata

  storage/ndb/test/src/NDBT_Test.cpp
    1.29 05/10/10 20:32:23 jonas@eel.(none)[jonas] +131 -12
    Wl1870 - ndb diskdata

  storage/ndb/test/src/NDBT_Tables.cpp
    1.17 05/10/10 20:32:23 jonas@eel.(none)[jonas] +153 -10
    Wl1870 - ndb diskdata

  storage/ndb/test/src/NDBT_ResultRow.cpp
    1.16 05/10/10 20:32:23 jonas@eel.(none)[jonas] +1 -1
    Wl1870 - ndb diskdata

  storage/ndb/test/src/HugoTransactions.cpp
    1.28 05/10/10 20:32:23 jonas@eel.(none)[jonas] +3 -2
    Wl1870 - ndb diskdata

  storage/ndb/test/src/HugoOperations.cpp
    1.27 05/10/10 20:32:23 jonas@eel.(none)[jonas] +7 -4
    Wl1870 - ndb diskdata

  storage/ndb/test/src/HugoCalculator.cpp
    1.21 05/10/10 20:32:23 jonas@eel.(none)[jonas] +41 -14
    Wl1870 - ndb diskdata

  storage/ndb/test/run-test/daily-basic-tests.txt
    1.35 05/10/10 20:32:23 jonas@eel.(none)[jonas] +90 -74
    Wl1870 - ndb diskdata

  storage/ndb/test/ndbapi/testPartitioning.cpp
    1.9 05/10/10 20:32:23 jonas@eel.(none)[jonas] +13 -4
    Wl1870 - ndb diskdata

  storage/ndb/test/ndbapi/testOperations.cpp
    1.11 05/10/10 20:32:23 jonas@eel.(none)[jonas] +3 -0
    Wl1870 - ndb diskdata

  storage/ndb/test/ndbapi/testOIBasic.cpp
    1.45 05/10/10 20:32:23 jonas@eel.(none)[jonas] +15 -7
    Wl1870 - ndb diskdata

  storage/ndb/test/ndbapi/testLcp.cpp
    1.7 05/10/10 20:32:23 jonas@eel.(none)[jonas] +316 -104
    Wl1870 - ndb diskdata

  storage/ndb/test/ndbapi/testDict.cpp
    1.25 05/10/10 20:32:23 jonas@eel.(none)[jonas] +102 -0
    Wl1870 - ndb diskdata

  storage/ndb/test/ndbapi/flexBench.cpp
    1.13 05/10/10 20:32:22 jonas@eel.(none)[jonas] +4 -4
    Wl1870 - ndb diskdata

  storage/ndb/test/ndbapi/create_tab.cpp
    1.10 05/10/10 20:32:22 jonas@eel.(none)[jonas] +33 -8
    Wl1870 - ndb diskdata

  storage/ndb/test/include/NdbSchemaOp.hpp
    1.14 05/10/10 20:32:22 jonas@eel.(none)[jonas] +3 -3
    Wl1870 - ndb diskdata

  storage/ndb/test/include/NdbRestarter.hpp
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -1
    Wl1870 - ndb diskdata

  storage/ndb/test/include/NDBT_Test.hpp
    1.17 05/10/10 20:32:22 jonas@eel.(none)[jonas] +9 -2
    Wl1870 - ndb diskdata

  storage/ndb/test/include/NDBT_Tables.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +4 -2
    Wl1870 - ndb diskdata

  storage/ndb/test/include/NDBT_Table.hpp
    1.12 05/10/10 20:32:22 jonas@eel.(none)[jonas] +3 -1
    Wl1870 - ndb diskdata

  storage/ndb/test/include/HugoTransactions.hpp
    1.11 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -1
    Wl1870 - ndb diskdata

  storage/ndb/test/include/HugoCalculator.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/ndberror.c
    1.43 05/10/10 20:32:22 jonas@eel.(none)[jonas] +24 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/TransporterFacade.cpp
    1.45 05/10/10 20:32:22 jonas@eel.(none)[jonas] +3 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/Ndbif.cpp
    1.34 05/10/10 20:32:22 jonas@eel.(none)[jonas] +9 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbScanOperation.cpp
    1.73 05/10/10 20:32:22 jonas@eel.(none)[jonas] +25 -22
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbReceiver.cpp
    1.17 05/10/10 20:32:22 jonas@eel.(none)[jonas] +12 -12
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbRecAttr.cpp
    1.24 05/10/10 20:32:22 jonas@eel.(none)[jonas] +205 -208
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbOperationSearch.cpp
    1.28 05/10/10 20:32:22 jonas@eel.(none)[jonas] +101 -45
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbOperationInt.cpp
    1.17 05/10/10 20:32:22 jonas@eel.(none)[jonas] +5 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbOperationExec.cpp
    1.21 05/10/10 20:32:22 jonas@eel.(none)[jonas] +3 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbOperationDefine.cpp
    1.23 05/10/10 20:32:22 jonas@eel.(none)[jonas] +32 -39
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbOperation.cpp
    1.17 05/10/10 20:32:22 jonas@eel.(none)[jonas] +9 -16
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbIndexOperation.cpp
    1.26 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp
    1.37 05/10/10 20:32:22 jonas@eel.(none)[jonas] +227 -34
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
    1.93 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1011 -331
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbDictionary.cpp
    1.41 05/10/10 20:32:22 jonas@eel.(none)[jonas] +446 -17
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/NdbBlob.cpp
    1.28 05/10/10 20:32:22 jonas@eel.(none)[jonas] +6 -5
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/Ndb.cpp
    1.59 05/10/10 20:32:22 jonas@eel.(none)[jonas] +10 -10
    Wl1870 - ndb diskdata

  storage/ndb/src/ndbapi/DictCache.cpp
    1.18 05/10/10 20:32:22 jonas@eel.(none)[jonas] +8 -9
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/pc.hpp
    1.11 05/10/10 20:32:22 jonas@eel.(none)[jonas] +8 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/SimulatedBlock.hpp
    1.17 05/10/10 20:32:22 jonas@eel.(none)[jonas] +12 -8
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/SimulatedBlock.cpp
    1.23 05/10/10 20:32:22 jonas@eel.(none)[jonas] +47 -6
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/SimBlockList.hpp
    1.3 05/10/10 20:32:22 jonas@eel.(none)[jonas] +0 -3
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/SafeCounter.cpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/SLList.hpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +68 -40
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/Makefile.am
    1.11 05/10/10 20:32:22 jonas@eel.(none)[jonas] +4 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/LongSignal.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/KeyDescriptor.hpp
    1.3 05/10/10 20:32:22 jonas@eel.(none)[jonas] +4 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/GlobalData.hpp
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +5 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/DataBuffer.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/DLList.hpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +73 -60
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/DLHashTable.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +64 -64
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/DLFifoList.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +143 -49
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/Configuration.cpp
    1.43 05/10/10 20:32:22 jonas@eel.(none)[jonas] +9 -12
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/vm/ArrayPool.hpp
    1.9 05/10/10 20:32:22 jonas@eel.(none)[jonas] +20 -10
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/suma/Suma.cpp
    1.27 05/10/10 20:32:22 jonas@eel.(none)[jonas] +13 -13
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/ndbfs/OpenFiles.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.hpp
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +5 -3
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp
    1.22 05/10/10 20:32:22 jonas@eel.(none)[jonas] +199 -114
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/ndbfs/Filename.hpp
    1.7 05/10/10 20:32:22 jonas@eel.(none)[jonas] +20 -22
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/ndbfs/Filename.cpp
    1.10 05/10/10 20:32:22 jonas@eel.(none)[jonas] +39 -66
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp
    1.7 05/10/10 20:32:22 jonas@eel.(none)[jonas] +10 -4
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp
    1.23 05/10/10 20:32:22 jonas@eel.(none)[jonas] +140 -42
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
    1.25 05/10/10 20:32:22 jonas@eel.(none)[jonas] +14 -4
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp
    1.15 05/10/10 20:32:22 jonas@eel.(none)[jonas] +9 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtux/Makefile.am
    1.9 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
    1.29 05/10/10 20:32:22 jonas@eel.(none)[jonas] +22 -22
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
    1.19 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -4
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
    1.18 05/10/10 20:32:22 jonas@eel.(none)[jonas] +3 -5
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
    1.21 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
    1.22 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -33
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
    1.43 05/10/10 20:32:22 jonas@eel.(none)[jonas] +8 -17
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/Makefile.am
    1.7 05/10/10 20:32:22 jonas@eel.(none)[jonas] +14 -4
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp
    1.15 05/10/10 20:32:22 jonas@eel.(none)[jonas] +255 -222
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +4 -4
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp
    1.3 05/10/10 20:32:22 jonas@eel.(none)[jonas] +22 -20
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +173 -85
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp
    1.23 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1088 -668
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupPageMap.cpp
    1.3 05/10/10 20:32:22 jonas@eel.(none)[jonas] +19 -19
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupPagMan.cpp
    1.7 05/10/10 20:32:22 jonas@eel.(none)[jonas] +43 -44
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
    1.16 05/10/10 20:32:22 jonas@eel.(none)[jonas] +720 -336
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
    1.15 05/10/10 20:32:22 jonas@eel.(none)[jonas] +355 -246
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp
    1.22 05/10/10 20:32:22 jonas@eel.(none)[jonas] +104 -731
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupFixAlloc.cpp
    1.3 05/10/10 20:32:22 jonas@eel.(none)[jonas] +86 -278
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
    1.22 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2050 -1164
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp
    1.10 05/10/10 20:32:22 jonas@eel.(none)[jonas] +92 -83
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +578 -501
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupBuffer.cpp
    1.10 05/10/10 20:32:22 jonas@eel.(none)[jonas] +81 -80
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +138 -264
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
    1.29 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1216 -956
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtup/AttributeOffset.hpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +7 -7
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
    1.92 05/10/10 20:32:22 jonas@eel.(none)[jonas] +11 -5
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp
    1.13 05/10/10 20:32:22 jonas@eel.(none)[jonas] +12 -25
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
    1.33 05/10/10 20:32:22 jonas@eel.(none)[jonas] +3 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
    1.80 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1425 -2277
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp
    1.18 05/10/10 20:32:22 jonas@eel.(none)[jonas] +19 -44
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
    1.40 05/10/10 20:32:22 jonas@eel.(none)[jonas] +169 -145
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbdih/Sysfile.hpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +6 -6
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbdih/Makefile.am
    1.7 05/10/10 20:32:22 jonas@eel.(none)[jonas] +10 -6
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
    1.38 05/10/10 20:32:22 jonas@eel.(none)[jonas] +14 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp
    1.11 05/10/10 20:32:22 jonas@eel.(none)[jonas] +9 -21
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp
    1.12 05/10/10 20:32:22 jonas@eel.(none)[jonas] +14 -4
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbdict/Makefile.am
    1.7 05/10/10 20:32:22 jonas@eel.(none)[jonas] +8 -3
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
    1.21 05/10/10 20:32:22 jonas@eel.(none)[jonas] +492 -120
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
    1.59 05/10/10 20:32:22 jonas@eel.(none)[jonas] +3527 -665
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
    1.62 05/10/10 20:32:22 jonas@eel.(none)[jonas] +347 -4439
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp
    1.19 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -99
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp
    1.25 05/10/10 20:32:22 jonas@eel.(none)[jonas] +27 -407
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
    1.24 05/10/10 20:32:22 jonas@eel.(none)[jonas] +5 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/backup/read.cpp
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +52 -7
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/backup/Makefile.am
    1.7 05/10/10 20:32:22 jonas@eel.(none)[jonas] +8 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/backup/FsBuffer.hpp
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +17 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/backup/BackupInit.cpp
    1.15 05/10/10 20:32:22 jonas@eel.(none)[jonas] +106 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/backup/BackupFormat.hpp
    1.3 05/10/10 20:32:22 jonas@eel.(none)[jonas] +13 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/backup/Backup.txt
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +62 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/backup/Backup.hpp
    1.13 05/10/10 20:32:22 jonas@eel.(none)[jonas] +48 -18
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/backup/Backup.cpp
    1.26 05/10/10 20:32:22 jonas@eel.(none)[jonas] +466 -248
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/blocks/Makefile.am
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +19 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/SimBlockList.cpp
    1.11 05/10/10 20:32:22 jonas@eel.(none)[jonas] +28 -24
    Wl1870 - ndb diskdata

  storage/ndb/src/kernel/Makefile.am
    1.14 05/10/10 20:32:22 jonas@eel.(none)[jonas] +4 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/common/debugger/signaldata/TuxMaint.cpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +5 -1
    Wl1870 - ndb diskdata

  storage/ndb/src/common/debugger/signaldata/SignalNames.cpp
    1.9 05/10/10 20:32:22 jonas@eel.(none)[jonas] +27 -30
    Wl1870 - ndb diskdata

  storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp
    1.13 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/common/debugger/signaldata/ScanTab.cpp
    1.17 05/10/10 20:32:22 jonas@eel.(none)[jonas] +3 -2
    Wl1870 - ndb diskdata

  storage/ndb/src/common/debugger/signaldata/FsReadWriteReq.cpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +8 -0
    Wl1870 - ndb diskdata

  storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp
    1.8 05/10/10 20:32:22 jonas@eel.(none)[jonas] +92 -3
    Wl1870 - ndb diskdata

  storage/ndb/src/common/debugger/BlockNames.cpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +5 -1
    Wl1870 - ndb diskdata

  storage/ndb/include/util/UtilBuffer.hpp
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +4 -2
    Wl1870 - ndb diskdata

  storage/ndb/include/util/Bitmask.hpp
    1.18 05/10/10 20:32:22 jonas@eel.(none)[jonas] +38 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/util/BaseString.hpp
    1.9 05/10/10 20:32:22 jonas@eel.(none)[jonas] +12 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/ndbapi/NdbRecAttr.hpp
    1.18 05/10/10 20:32:22 jonas@eel.(none)[jonas] +13 -45
    Wl1870 - ndb diskdata

  storage/ndb/include/ndbapi/NdbOperation.hpp
    1.34 05/10/10 20:32:22 jonas@eel.(none)[jonas] +68 -33
    Wl1870 - ndb diskdata

  storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp
    1.23 05/10/10 20:32:22 jonas@eel.(none)[jonas] +28 -6
    Wl1870 - ndb diskdata

  storage/ndb/include/ndbapi/NdbDictionary.hpp
    1.57 05/10/10 20:32:22 jonas@eel.(none)[jonas] +226 -2
    Wl1870 - ndb diskdata

  storage/ndb/include/ndb_constants.h
    1.12 05/10/10 20:32:22 jonas@eel.(none)[jonas] +16 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/trigger_definitions.h
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +12 -10
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/TuxMaint.hpp
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +5 -2
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/TupKey.hpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -4
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/TupFrag.hpp
    1.9 05/10/10 20:32:22 jonas@eel.(none)[jonas] +2 -1
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/TcKeyReq.hpp
    1.7 05/10/10 20:32:22 jonas@eel.(none)[jonas] +18 -37
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/StartFragReq.hpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1 -2
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/ScanTab.hpp
    1.16 05/10/10 20:32:22 jonas@eel.(none)[jonas] +19 -1
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/ScanFrag.hpp
    1.12 05/10/10 20:32:22 jonas@eel.(none)[jonas] +18 -1
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/LqhKey.hpp
    1.3 05/10/10 20:32:22 jonas@eel.(none)[jonas] +22 -3
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/LqhFrag.hpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +13 -13
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/LCP.hpp
    1.3 05/10/10 20:32:22 jonas@eel.(none)[jonas] +66 -1
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/KeyInfo.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/GetTabInfo.hpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +8 -2
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/FsRef.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +11 -6
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/FsReadWriteReq.hpp
    1.3 05/10/10 20:32:22 jonas@eel.(none)[jonas] +21 -2
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/FsOpenReq.hpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +57 -4
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/FsConf.hpp
    1.3 05/10/10 20:32:22 jonas@eel.(none)[jonas] +9 -5
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/FsCloseReq.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +3 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/DumpStateOrd.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +7 -1
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/DictTabInfo.hpp
    1.22 05/10/10 20:32:22 jonas@eel.(none)[jonas] +163 -15
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/CreateTable.hpp
    1.5 05/10/10 20:32:22 jonas@eel.(none)[jonas] +5 -1
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/CreateIndx.hpp
    1.8 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/BackupImpl.hpp
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +8 -2
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/AttrInfo.hpp
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/signaldata/AlterTable.hpp
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +17 -1
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/ndb_limits.h
    1.19 05/10/10 20:32:22 jonas@eel.(none)[jonas] +11 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/kernel_types.h
    1.4 05/10/10 20:32:22 jonas@eel.(none)[jonas] +32 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/GlobalSignalNumbers.h
    1.13 05/10/10 20:32:22 jonas@eel.(none)[jonas] +87 -38
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/BlockNumbers.h
    1.6 05/10/10 20:32:22 jonas@eel.(none)[jonas] +9 -1
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/AttributeHeader.hpp
    1.12 05/10/10 20:32:22 jonas@eel.(none)[jonas] +1 -0
    Wl1870 - ndb diskdata

  storage/ndb/include/kernel/AttributeDescriptor.hpp
    1.8 05/10/10 20:32:22 jonas@eel.(none)[jonas] +43 -16
    Wl1870 - ndb diskdata

  sql/sql_yacc.yy
    1.416 05/10/10 20:32:20 jonas@eel.(none)[jonas] +452 -2
    Wl1870 - ndb diskdata

  sql/sql_parse.cc
    1.478 05/10/10 20:32:20 jonas@eel.(none)[jonas] +6 -0
    Wl1870 - ndb diskdata

  sql/sql_lex.h
    1.200 05/10/10 20:32:20 jonas@eel.(none)[jonas] +8 -0
    Wl1870 - ndb diskdata

  sql/share/errmsg.txt
    1.50 05/10/10 20:32:20 jonas@eel.(none)[jonas] +14 -0
    Wl1870 - ndb diskdata

  sql/mysql_priv.h
    1.338 05/10/10 20:32:20 jonas@eel.(none)[jonas] +1 -0
    Wl1870 - ndb diskdata

  sql/lex.h
    1.144 05/10/10 20:32:20 jonas@eel.(none)[jonas] +18 -1
    Wl1870 - ndb diskdata

  sql/handler.h
    1.161 05/10/10 20:32:19 jonas@eel.(none)[jonas] +79 -1
    Wl1870 - ndb diskdata

  sql/ha_ndbcluster.h
    1.97 05/10/10 20:32:19 jonas@eel.(none)[jonas] +1 -0
    Wl1870 - ndb diskdata

  sql/ha_ndbcluster.cc
    1.213 05/10/10 20:32:19 jonas@eel.(none)[jonas] +255 -20
    Wl1870 - ndb diskdata

  sql/Makefile.am
    1.116 05/10/10 20:32:14 jonas@eel.(none)[jonas] +1 -0
    Wl1870 - ndb diskdata

  mysql-test/t/ndb_restore.test
    1.11 05/10/10 20:32:14 jonas@eel.(none)[jonas] +2 -1
    Wl1870 - ndb diskdata

  mysql-test/t/ndb_autodiscover.test
    1.23 05/10/10 20:32:14 jonas@eel.(none)[jonas] +2 -2
    Wl1870 - ndb diskdata

  mysql-test/t/ndb_alter_table.test
    1.27 05/10/10 20:32:14 jonas@eel.(none)[jonas] +4 -4
    Wl1870 - ndb diskdata

  mysql-test/r/ndb_restore.result
    1.6 05/10/10 20:32:14 jonas@eel.(none)[jonas] +0 -20
    Wl1870 - ndb diskdata

  mysql-test/r/ndb_partition_key.result
    1.6 05/10/10 20:32:14 jonas@eel.(none)[jonas] +4 -4
    Wl1870 - ndb diskdata

  mysql-test/r/ndb_autodiscover.result
    1.28 05/10/10 20:32:14 jonas@eel.(none)[jonas] +2 -2
    Wl1870 - ndb diskdata

  mysql-test/r/ndb_alter_table.result
    1.32 05/10/10 20:32:14 jonas@eel.(none)[jonas] +4 -4
    Wl1870 - ndb diskdata

  mysql-test/ndb/ndbcluster.sh
    1.43 05/10/10 20:32:14 jonas@eel.(none)[jonas] +1 -1
    Wl1870 - ndb diskdata

  libmysqld/Makefile.am
    1.67 05/10/10 20:32:13 jonas@eel.(none)[jonas] +1 -1
    Wl1870 - ndb diskdata

  configure.in
    1.304 05/10/10 20:32:13 jonas@eel.(none)[jonas] +2 -1
    Wl1870 - ndb diskdata

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	jonas
# Host:	eel.(none)
# Root:	/home/jonas/src/51-clean

--- 1.303/configure.in	2005-10-07 01:06:16 +02:00
+++ 1.304/configure.in	2005-10-10 20:32:13 +02:00
@@ -1874,7 +1874,8 @@
   shmget shmat shmdt shmctl sigaction sigemptyset sigaddset \
   sighold sigset sigthreadmask \
   snprintf socket stpcpy strcasecmp strerror strsignal strnlen strpbrk strstr strtol \
-  strtoll strtoul strtoull tell tempnam thr_setconcurrency vidattr)
+  strtoll strtoul strtoull tell tempnam thr_setconcurrency vidattr \
+  posix_fallocate)
 
 #
 #

--- 1.115/sql/Makefile.am	2005-10-06 10:25:57 +02:00
+++ 1.116/sql/Makefile.am	2005-10-10 20:32:14 +02:00
@@ -99,6 +99,7 @@
                         tztime.cc my_time.c my_decimal.cc\
 			sp_head.cc sp_pcontext.cc  sp_rcontext.cc sp.cc \
 			sp_cache.cc parse_file.cc sql_trigger.cc \
+                        sql_tablespace.cc \
 			examples/ha_example.cc ha_archive.cc \
 			examples/ha_tina.cc ha_blackhole.cc \
                         ha_partition.cc sql_partition.cc \

--- 1.160/sql/handler.h	2005-10-06 10:31:19 +02:00
+++ 1.161/sql/handler.h	2005-10-10 20:32:19 +02:00
@@ -648,7 +648,7 @@
 {
   CHARSET_INFO *table_charset, *default_table_charset;
   LEX_STRING connect_string;
-  const char *comment,*password;
+  const char *comment,*password, *tablespace;
   const char *data_file_name, *index_file_name;
   const char *alias;
   ulonglong max_rows,min_rows;
@@ -667,6 +667,7 @@
   bool table_existed;			/* 1 in create if table existed */
   bool frm_only;                        /* 1 if no ha_create_table() */
   bool varchar;                         /* 1 if table has a VARCHAR */
+  bool store_on_disk;                   /* 1 if table stored on disk */
 } HA_CREATE_INFO;
 
 
@@ -740,6 +741,81 @@
   byte *end_of_used_area;     /* End of area that was used by handler */
 } HANDLER_BUFFER;
 
+/*
+  These structures are used to pass information from a set of SQL commands
+  on add/drop/change tablespace definitions to the proper storage engine.
+*/
+#define UNDEF_NODEGROUP 65535
+enum ts_command_type
+{
+  TS_CMD_NOT_DEFINED = -1,
+  CREATE_TABLESPACE = 0,
+  ALTER_TABLESPACE = 1,
+  CREATE_LOGFILE_GROUP = 2,
+  ALTER_LOGFILE_GROUP = 3,
+  DROP_TABLESPACE = 4,
+  DROP_LOGFILE_GROUP = 5,
+  CHANGE_FILE_TABLESPACE = 6,
+  ALTER_ACCESS_MODE_TABLESPACE = 7
+};
+
+enum ts_alter_tablespace_type
+{
+  TS_ALTER_TABLESPACE_TYPE_NOT_DEFINED = -1,
+  ALTER_TABLESPACE_ADD_FILE = 1,
+  ALTER_TABLESPACE_DROP_FILE = 2
+};
+
+enum tablespace_access_mode
+{
+  TS_NOT_DEFINED= -1,
+  TS_READ_ONLY = 0,
+  TS_READ_WRITE = 1,
+  TS_NOT_ACCESSIBLE = 2
+};
+
+class st_alter_tablespace : public Sql_alloc
+{
+  public:
+  char *tablespace_name;
+  char *logfile_group_name;
+  enum ts_command_type ts_cmd_type;
+  enum ts_alter_tablespace_type ts_alter_tablespace_type;
+  char *data_file_name;
+  char *undo_file_name;
+  char *redo_file_name;
+  ulonglong extent_size;
+  ulonglong undo_buffer_size;
+  ulonglong redo_buffer_size;
+  ulonglong initial_size;
+  ulonglong autoextend_size;
+  ulonglong max_size;
+  uint nodegroup_id;
+  enum db_type storage_engine;
+  bool wait_until_completed;
+  char *ts_comment;
+  enum tablespace_access_mode ts_access_mode;
+  st_alter_tablespace()
+  {
+    tablespace_name= NULL;
+    logfile_group_name= "DEFAULT_LG"; //Default log file group
+    ts_cmd_type= TS_CMD_NOT_DEFINED;
+    data_file_name= NULL;
+    undo_file_name= NULL;
+    redo_file_name= NULL;
+    extent_size= 1024*1024;        //Default 1 MByte
+    undo_buffer_size= 8*1024*1024; //Default 8 MByte
+    redo_buffer_size= 8*1024*1024; //Default 8 MByte
+    initial_size= 128*1024*1024;   //Default 128 MByte
+    autoextend_size= 0;            //No autoextension as default
+    max_size= 0;                   //Max size == initial size => no extension
+    storage_engine= DB_TYPE_UNKNOWN;
+    nodegroup_id= UNDEF_NODEGROUP;
+    wait_until_completed= TRUE;
+    ts_comment= NULL;
+    ts_access_mode= TS_NOT_DEFINED;
+  }
+};
 
 class handler :public Sql_alloc
 {
@@ -1200,6 +1276,8 @@
   virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt)
   { return HA_ADMIN_NOT_IMPLEMENTED; }
   virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt)
+  { return HA_ADMIN_NOT_IMPLEMENTED; }
+  virtual int alter_tablespace(st_alter_tablespace *alter_tablespace_info)
   { return HA_ADMIN_NOT_IMPLEMENTED; }
   /* end of the list of admin commands */
 

--- 1.143/sql/lex.h	2005-09-03 01:06:52 +02:00
+++ 1.144/sql/lex.h	2005-10-10 20:32:20 +02:00
@@ -59,6 +59,7 @@
   { "<<",		SYM(SHIFT_LEFT)},
   { ">>",		SYM(SHIFT_RIGHT)},
   { "<=>",		SYM(EQUAL_SYM)},
+  { "ACCESSIBLE",	SYM(ACCESSIBLE_SYM)},
   { "ACTION",		SYM(ACTION)},
   { "ADD",		SYM(ADD)},
   { "AFTER",		SYM(AFTER_SYM)},
@@ -75,6 +76,7 @@
   { "ASCII",		SYM(ASCII_SYM)},
   { "ASENSITIVE",       SYM(ASENSITIVE_SYM)},
   { "AUTO_INCREMENT",	SYM(AUTO_INC)},
+  { "AUTOEXTEND_SIZE",	SYM(AUTOEXTEND_SIZE_SYM)},
   { "AVG",		SYM(AVG_SYM)},
   { "AVG_ROW_LENGTH",	SYM(AVG_ROW_LENGTH)},
   { "BACKUP",	        SYM(BACKUP_SYM)},
@@ -139,6 +141,7 @@
   { "DATA",		SYM(DATA_SYM)},
   { "DATABASE",		SYM(DATABASE)},
   { "DATABASES",	SYM(DATABASES)},
+  { "DATAFILE", 	SYM(DATAFILE_SYM)},
   { "DATE",		SYM(DATE_SYM)},
   { "DATETIME",		SYM(DATETIME)},
   { "DAY",		SYM(DAY_SYM)},
@@ -162,6 +165,7 @@
   { "DIRECTORY",	SYM(DIRECTORY_SYM)},
   { "DISABLE",		SYM(DISABLE_SYM)},
   { "DISCARD",		SYM(DISCARD)},
+  { "DISK",		SYM(DISK_SYM)},
   { "DISTINCT",		SYM(DISTINCT)},
   { "DISTINCTROW",	SYM(DISTINCT)},	/* Access likes this */
   { "DIV",		SYM(DIV_SYM)},
@@ -191,6 +195,7 @@
   { "EXPANSION",	SYM(EXPANSION_SYM)},
   { "EXPLAIN",		SYM(DESCRIBE)},
   { "EXTENDED",		SYM(EXTENDED_SYM)},
+  { "EXTENT_SIZE",	SYM(EXTENT_SIZE_SYM)},
   { "FALSE",		SYM(FALSE_SYM)},
   { "FAST",		SYM(FAST_SYM)},
   { "FETCH",            SYM(FETCH_SYM)},
@@ -239,6 +244,7 @@
   { "INDEX",		SYM(INDEX_SYM)},
   { "INDEXES",		SYM(INDEXES)},
   { "INFILE",		SYM(INFILE)},
+  { "INITIAL_SIZE",	SYM(INITIAL_SIZE_SYM)},
   { "INNER",		SYM(INNER_SYM)},
   { "INNOBASE",		SYM(INNOBASE_SYM)},
   { "INNODB",		SYM(INNOBASE_SYM)},
@@ -289,6 +295,7 @@
   { "LOCALTIMESTAMP",	SYM(NOW_SYM)},
   { "LOCK",		SYM(LOCK_SYM)},
   { "LOCKS",		SYM(LOCKS_SYM)},
+  { "LOGFILE",		SYM(LOGFILE_SYM)},
   { "LOGS",		SYM(LOGS_SYM)},
   { "LONG",		SYM(LONG_SYM)},
   { "LONGBLOB",		SYM(LONGBLOB)},
@@ -314,6 +321,7 @@
   { "MAX_CONNECTIONS_PER_HOUR", SYM(MAX_CONNECTIONS_PER_HOUR)},
   { "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR)},
   { "MAX_ROWS",		SYM(MAX_ROWS)},
+  { "MAX_SIZE",		SYM(MAX_SIZE_SYM)},
   { "MAX_UPDATES_PER_HOUR", SYM(MAX_UPDATES_PER_HOUR)},
   { "MAX_USER_CONNECTIONS", SYM(MAX_USER_CONNECTIONS_SYM)},
   { "MAXVALUE",         SYM(MAX_VALUE_SYM)},
@@ -321,6 +329,7 @@
   { "MEDIUMBLOB",	SYM(MEDIUMBLOB)},
   { "MEDIUMINT",	SYM(MEDIUMINT)},
   { "MEDIUMTEXT",	SYM(MEDIUMTEXT)},
+  { "MEMORY",		SYM(MEMORY_SYM)},
   { "MERGE",		SYM(MERGE_SYM)},
   { "MICROSECOND",	SYM(MICROSECOND_SYM)},
   { "MIDDLEINT",	SYM(MEDIUMINT)},	/* For powerbuilder */
@@ -348,7 +357,8 @@
   { "NEW",              SYM(NEW_SYM)},
   { "NEXT",		SYM(NEXT_SYM)},
   { "NO",		SYM(NO_SYM)},
-  { "NODEGROUP",        SYM(NODEGROUP_SYM)},
+  { "NO_WAIT",		SYM(NO_WAIT_SYM)},
+  { "NODEGROUP",	SYM(NODEGROUP_SYM)},
   { "NONE",		SYM(NONE_SYM)},
   { "NOT",		SYM(NOT_SYM)},
   { "NO_WRITE_TO_BINLOG",  SYM(NO_WRITE_TO_BINLOG)},
@@ -397,9 +407,13 @@
   { "RAID_TYPE",	SYM(RAID_TYPE)},
   { "RANGE",            SYM(RANGE_SYM)},
   { "READ",		SYM(READ_SYM)},
+  { "READ_ONLY",	SYM(READ_ONLY_SYM)},
+  { "READ_WRITE",	SYM(READ_WRITE_SYM)},
   { "READS",		SYM(READS_SYM)},
   { "REAL",		SYM(REAL)},
   { "RECOVER",          SYM(RECOVER_SYM)},
+  { "REDO_BUFFER_SIZE",	SYM(REDO_BUFFER_SIZE_SYM)},
+  { "REDOFILE",         SYM(REDOFILE_SYM)},
   { "REDUNDANT",	SYM(REDUNDANT_SYM)},
   { "REFERENCES",	SYM(REFERENCES)},
   { "REGEXP",		SYM(REGEXP)},
@@ -519,6 +533,8 @@
   { "TYPES",		SYM(TYPES_SYM)},
   { "UNCOMMITTED",	SYM(UNCOMMITTED_SYM)},
   { "UNDEFINED",	SYM(UNDEFINED_SYM)},
+  { "UNDO_BUFFER_SIZE",	SYM(UNDO_BUFFER_SIZE_SYM)},
+  { "UNDOFILE", 	SYM(UNDOFILE_SYM)},
   { "UNDO",             SYM(UNDO_SYM)},
   { "UNICODE",	        SYM(UNICODE_SYM)},
   { "UNION",	        SYM(UNION_SYM)},
@@ -544,6 +560,7 @@
   { "VARCHARACTER",	SYM(VARCHAR)},
   { "VARIABLES",	SYM(VARIABLES)},
   { "VARYING",		SYM(VARYING)},
+  { "WAIT",		SYM(WAIT_SYM)},
   { "WARNINGS",		SYM(WARNINGS)},
   { "WEEK",		SYM(WEEK_SYM)},
   { "WHEN",		SYM(WHEN_SYM)},

--- 1.337/sql/mysql_priv.h	2005-10-09 19:09:43 +02:00
+++ 1.338/sql/mysql_priv.h	2005-10-10 20:32:20 +02:00
@@ -679,6 +679,7 @@
 bool mysql_xa_recover(THD *thd);
 
 bool check_simple_select();
+int mysql_alter_tablespace(st_alter_tablespace *ts_info);
 
 SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
 int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,

--- 1.199/sql/sql_lex.h	2005-10-06 10:26:01 +02:00
+++ 1.200/sql/sql_lex.h	2005-10-10 20:32:20 +02:00
@@ -25,6 +25,7 @@
 class sp_name;
 class sp_instr;
 class sp_pcontext;
+class st_alter_tablespace;
 class partition_info;
 
 /*
@@ -91,6 +92,7 @@
   SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER,
   SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE,
   SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER,
+  SQLCOM_ALTER_TABLESPACE,
   /* This should be the last !!! */
 
   SQLCOM_END
@@ -904,6 +906,12 @@
     during replication ("LOCAL 'filename' REPLACE INTO" part).
   */
   uchar *fname_start, *fname_end;
+
+  /*
+    Reference to a struct that contains information in various commands
+    to add/create/drop/change table spaces.
+  */
+  st_alter_tablespace *alter_tablespace_info;
 
   st_lex();
 

--- 1.477/sql/sql_parse.cc	2005-10-09 19:09:47 +02:00
+++ 1.478/sql/sql_parse.cc	2005-10-10 20:32:20 +02:00
@@ -4742,6 +4742,12 @@
   case SQLCOM_XA_RECOVER:
     res= mysql_xa_recover(thd);
     break;
+  case SQLCOM_ALTER_TABLESPACE:
+    if (check_access(thd, ALTER_ACL, thd->db, 0, 1, 0, thd->db ? is_schema_db(thd->db) : 0))
+      break;
+    if (!(res= mysql_alter_tablespace(lex->alter_tablespace_info)))
+      send_ok(thd);
+    break;
   default:
     DBUG_ASSERT(0);                             /* Impossible */
     send_ok(thd);

--- 1.415/sql/sql_yacc.yy	2005-10-06 10:26:03 +02:00
+++ 1.416/sql/sql_yacc.yy	2005-10-10 20:32:20 +02:00
@@ -119,6 +119,7 @@
 %token  END_OF_INPUT
 
 %token  ABORT_SYM
+%token  ACCESSIBLE_SYM
 %token  ACTION
 %token  ADD
 %token  ADDDATE_SYM
@@ -138,6 +139,7 @@
 %token  ASENSITIVE_SYM
 %token  ATAN
 %token  AUTO_INC
+%token  AUTOEXTEND_SIZE_SYM
 %token  AVG_ROW_LENGTH
 %token  AVG_SYM
 %token  BACKUP_SYM
@@ -206,6 +208,7 @@
 %token  CURTIME
 %token  DATABASE
 %token  DATABASES
+%token  DATAFILE_SYM
 %token  DATA_SYM
 %token  DATETIME
 %token  DATE_ADD_INTERVAL
@@ -235,6 +238,7 @@
 %token  DIRECTORY_SYM
 %token  DISABLE_SYM
 %token  DISCARD
+%token  DISK_SYM
 %token  DISTINCT
 %token  DIV_SYM
 %token  DOUBLE_SYM
@@ -267,6 +271,7 @@
 %token  EXPANSION_SYM
 %token  EXPORT_SET
 %token  EXTENDED_SYM
+%token  EXTENT_SIZE_SYM
 %token  EXTRACT_SYM
 %token  FALSE_SYM
 %token  FAST_SYM
@@ -329,6 +334,7 @@
 %token  INDEXES
 %token  INDEX_SYM
 %token  INFILE
+%token  INITIAL_SIZE_SYM
 %token  INNER_SYM
 %token  INNOBASE_SYM
 %token  INOUT_SYM
@@ -374,6 +380,7 @@
 %token  LOCATOR_SYM
 %token  LOCKS_SYM
 %token  LOCK_SYM
+%token  LOGFILE_SYM
 %token  LOGS_SYM
 %token  LOG_SYM
 %token  LONGBLOB
@@ -404,6 +411,7 @@
 %token  MAX_CONNECTIONS_PER_HOUR
 %token  MAX_QUERIES_PER_HOUR
 %token  MAX_ROWS
+%token  MAX_SIZE_SYM
 %token  MAX_SYM
 %token  MAX_UPDATES_PER_HOUR
 %token  MAX_USER_CONNECTIONS_SYM
@@ -412,6 +420,7 @@
 %token  MEDIUMINT
 %token  MEDIUMTEXT
 %token  MEDIUM_SYM
+%token  MEMORY_SYM
 %token  MERGE_SYM
 %token  MICROSECOND_SYM
 %token  MIGRATE_SYM
@@ -448,6 +457,7 @@
 %token  NOT_SYM
 %token  NOW_SYM
 %token  NO_SYM
+%token  NO_WAIT_SYM
 %token  NO_WRITE_TO_BINLOG
 %token  NULL_SYM
 %token  NUM
@@ -501,9 +511,13 @@
 %token  RAND
 %token  RANGE_SYM
 %token  READS_SYM
+%token  READ_ONLY_SYM
 %token  READ_SYM
+%token  READ_WRITE_SYM
 %token  REAL
 %token  RECOVER_SYM
+%token  REDO_BUFFER_SIZE_SYM
+%token  REDOFILE_SYM
 %token  REDUNDANT_SYM
 %token  REFERENCES
 %token  REGEXP
@@ -625,6 +639,8 @@
 %token  ULONGLONG_NUM
 %token  UNCOMMITTED_SYM
 %token  UNDEFINED_SYM
+%token  UNDO_BUFFER_SIZE_SYM
+%token  UNDOFILE_SYM
 %token  UNDERSCORE_CHARSET
 %token  UNDO_SYM
 %token  UNICODE_SYM
@@ -654,6 +670,7 @@
 %token  VARIANCE_SYM
 %token  VARYING
 %token  VIEW_SYM
+%token  WAIT_SYM
 %token  WARNINGS
 %token  WEEK_SYM
 %token  WHEN_SYM
@@ -721,7 +738,7 @@
 	ulong_num raid_types merge_insert_types
 
 %type <ulonglong_number>
-	ulonglong_num
+	ulonglong_num size_number
 
 %type <longlong_number>
         part_bit_expr
@@ -1285,6 +1302,16 @@
 	  }
 	  opt_view_list AS select_view_init check_option
 	  {}
+        | CREATE LOGFILE_SYM GROUP logfile_group_info 
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP;
+          }
+        | CREATE TABLESPACE tablespace_info
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE;
+          }
         | CREATE TRIGGER_SYM sp_name trg_action_time trg_event 
           ON table_ident FOR_SYM EACH_SYM ROW_SYM
           {
@@ -2546,6 +2573,382 @@
           | DELETE_SYM
             { Lex->trg_chistics.event= TRG_EVENT_DELETE; }
           ;
+/*
+  This part of the parser contains common code for all TABLESPACE
+  commands.
+  CREATE TABLESPACE name ...
+  ALTER TABLESPACE name CHANGE DATAFILE ...
+  ALTER TABLESPACE name ADD DATAFILE ...
+  ALTER TABLESPACE name access_mode
+  CREATE LOGFILE GROUP name ...
+  ALTER LOGFILE GROUP name ADD UNDOFILE ..
+  ALTER LOGFILE GROUP name ADD REDOFILE ..
+  DROP TABLESPACE name
+  DROP LOGFILE GROUP name
+*/
+change_tablespace_access:
+          tablespace_name
+          ts_access_mode
+          ;
+
+change_tablespace_info:
+          tablespace_name
+          CHANGE ts_datafile
+          change_ts_option_list
+          ;
+
+tablespace_info:
+          tablespace_name
+          ADD ts_datafile
+          opt_logfile_group_name
+          tablespace_option_list
+          ;
+
+opt_logfile_group_name:
+          /* empty */ {}
+          | USE_SYM LOGFILE_SYM GROUP ident
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->logfile_group_name= $4.str;
+          };
+
+alter_tablespace_info:
+          tablespace_name
+          ADD ts_datafile
+          alter_tablespace_option_list 
+	  { 
+	    Lex->alter_tablespace_info->ts_alter_tablespace_type= ALTER_TABLESPACE_ADD_FILE; 
+          }
+          |
+          tablespace_name
+          DROP ts_datafile
+          alter_tablespace_option_list 
+	  { 
+	    Lex->alter_tablespace_info->ts_alter_tablespace_type= ALTER_TABLESPACE_DROP_FILE; 
+          };
+
+logfile_group_info:
+          logfile_group_name
+          add_log_file
+          logfile_group_option_list
+          ;
+
+alter_logfile_group_info:
+          logfile_group_name
+          add_log_file
+          alter_logfile_group_option_list
+          ;
+
+add_log_file:
+          ADD lg_undofile
+          | ADD lg_redofile
+          ;
+
+change_ts_option_list:
+          /* empty */ {}
+          change_ts_options
+          ;
+
+change_ts_options:
+          change_ts_option
+          | change_ts_options change_ts_option
+          | change_ts_options ',' change_ts_option
+          ;
+
+change_ts_option:
+          opt_ts_initial_size
+          | opt_ts_autoextend_size
+          | opt_ts_max_size
+          ;
+
+tablespace_option_list:
+          /* empty */ {}
+          tablespace_options
+          ;
+
+tablespace_options:
+          tablespace_option
+          | tablespace_options tablespace_option
+          | tablespace_options ',' tablespace_option
+          ;
+
+tablespace_option:
+          opt_ts_initial_size
+          | opt_ts_autoextend_size
+          | opt_ts_max_size
+          | opt_ts_extent_size
+          | opt_ts_nodegroup
+          | opt_ts_engine
+          | ts_wait
+          | opt_ts_comment
+          ;
+
+alter_tablespace_option_list:
+          /* empty */ {}
+          alter_tablespace_options
+          ;
+
+alter_tablespace_options:
+          alter_tablespace_option
+          | alter_tablespace_options alter_tablespace_option
+          | alter_tablespace_options ',' alter_tablespace_option
+          ;
+
+alter_tablespace_option:
+          opt_ts_initial_size
+          | opt_ts_autoextend_size
+          | opt_ts_max_size
+          | opt_ts_engine
+          | ts_wait
+          ;
+
+logfile_group_option_list:
+          /* empty */ {}
+          logfile_group_options
+          ;
+
+logfile_group_options:
+          logfile_group_option
+          | logfile_group_options logfile_group_option
+          | logfile_group_options ',' logfile_group_option
+          ;
+
+logfile_group_option:
+          opt_ts_initial_size
+          | opt_ts_undo_buffer_size
+          | opt_ts_redo_buffer_size
+          | opt_ts_nodegroup
+          | opt_ts_engine
+          | ts_wait
+          | opt_ts_comment
+          ;
+
+alter_logfile_group_option_list:
+          /* empty */ {}
+          alter_logfile_group_options
+          ;
+
+alter_logfile_group_options:
+          alter_logfile_group_option
+          | alter_logfile_group_options alter_logfile_group_option
+          | alter_logfile_group_options ',' alter_logfile_group_option
+          ;
+
+alter_logfile_group_option:
+          opt_ts_initial_size
+          | opt_ts_engine
+          | ts_wait
+          ;
+
+
+ts_datafile:
+          DATAFILE_SYM TEXT_STRING_sys
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->data_file_name= $2.str;
+          };
+
+lg_undofile:
+          UNDOFILE_SYM TEXT_STRING_sys
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->undo_file_name= $2.str;
+          };
+
+lg_redofile:
+          REDOFILE_SYM TEXT_STRING_sys
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->redo_file_name= $2.str;
+          };
+
+tablespace_name:
+          ident
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info= new st_alter_tablespace();
+            lex->alter_tablespace_info->tablespace_name= $1.str;
+            lex->sql_command= SQLCOM_ALTER_TABLESPACE;
+          };
+
+logfile_group_name:
+          ident
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info= new st_alter_tablespace();
+            lex->alter_tablespace_info->logfile_group_name= $1.str;
+            lex->sql_command= SQLCOM_ALTER_TABLESPACE;
+          };
+
+ts_access_mode:
+          READ_ONLY_SYM
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_access_mode= TS_READ_ONLY;
+          }
+          | READ_WRITE_SYM
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_access_mode= TS_READ_WRITE;
+          }
+          | NOT_SYM ACCESSIBLE_SYM
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_access_mode= TS_NOT_ACCESSIBLE;
+          };
+
+opt_ts_initial_size:
+          INITIAL_SIZE_SYM opt_equal size_number
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->initial_size= $3;
+          };
+
+opt_ts_autoextend_size:
+          AUTOEXTEND_SIZE_SYM opt_equal size_number
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->autoextend_size= $3;
+          };
+
+opt_ts_max_size:
+          MAX_SIZE_SYM opt_equal size_number
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->max_size= $3;
+          };
+
+opt_ts_extent_size:
+          EXTENT_SIZE_SYM opt_equal size_number
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->extent_size= $3;
+          };
+
+opt_ts_undo_buffer_size:
+          UNDO_BUFFER_SIZE_SYM opt_equal size_number
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->undo_buffer_size= $3;
+          };
+
+opt_ts_redo_buffer_size:
+          REDO_BUFFER_SIZE_SYM opt_equal size_number
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->redo_buffer_size= $3;
+          };
+
+opt_ts_nodegroup:
+          NODEGROUP_SYM opt_equal ulong_num
+          {
+            LEX *lex= Lex;
+            if (lex->alter_tablespace_info->nodegroup_id != UNDEF_NODEGROUP)
+            {
+              my_error(ER_TABLESPACE_OPTION_ONLY_ONCE,MYF(0),"NODEGROUP");
+              YYABORT;
+            }
+            lex->alter_tablespace_info->nodegroup_id= $3;
+          };
+
+opt_ts_comment:
+          COMMENT_SYM opt_equal TEXT_STRING_sys
+          {
+            LEX *lex= Lex;
+            if (lex->alter_tablespace_info->ts_comment != NULL)
+            {
+              my_error(ER_TABLESPACE_OPTION_ONLY_ONCE,MYF(0),"COMMENT");
+              YYABORT;
+            }
+            lex->alter_tablespace_info->ts_comment= $3.str;
+          };
+
+opt_ts_engine:
+          opt_storage ENGINE_SYM opt_equal storage_engines
+          {
+            LEX *lex= Lex;
+            if (lex->alter_tablespace_info->storage_engine != DB_TYPE_UNKNOWN)
+            {
+              my_error(ER_TABLESPACE_OPTION_ONLY_ONCE,MYF(0),
+                       "STORAGE ENGINE");
+              YYABORT;
+            }
+            lex->alter_tablespace_info->storage_engine= $4;
+          };
+
+opt_ts_wait:
+          /* empty */ 
+          | ts_wait
+          ;
+
+ts_wait:
+          WAIT_SYM
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->wait_until_completed= TRUE;
+          }
+          | NO_WAIT_SYM
+          {
+            LEX *lex= Lex;
+            if (!(lex->alter_tablespace_info->wait_until_completed))
+            {
+              my_error(ER_TABLESPACE_OPTION_ONLY_ONCE,MYF(0),"NO_WAIT");
+              YYABORT;
+            }
+            lex->alter_tablespace_info->wait_until_completed= FALSE;
+          };
+
+size_number:
+          ulong_num { $$= $1;}
+          | IDENT
+          {
+            ulonglong number, test_number;
+            uint text_shift_number= 0;
+            longlong prefix_number;
+            char *end_ptr;
+            char *start_ptr= $1.str;
+            uint str_len= strlen(start_ptr);
+            int error;
+            prefix_number= my_strtoll10(start_ptr, &end_ptr, &error);
+            if ((start_ptr + str_len - 1) == end_ptr)
+            {
+              switch (end_ptr[0])
+              {
+                case 'g':
+                case 'G':
+                  text_shift_number+=10;
+                case 'm':
+                case 'M':
+                  text_shift_number+=10;
+                case 'k':
+                case 'K':
+                  text_shift_number+=10;
+                  break;
+                default:
+                {
+                  my_error(ER_WRONG_SIZE_NUMBER, MYF(0));
+                  YYABORT;
+                }
+              }
+              if (prefix_number >> 31)
+              {
+                my_error(ER_SIZE_OVERFLOW_ERROR, MYF(0));
+                YYABORT;
+              }
+              number= prefix_number << text_shift_number;
+            }
+            else
+            {
+              my_error(ER_WRONG_SIZE_NUMBER, MYF(0));
+              YYABORT;
+            }
+            $$= number;
+          }
+          ;
+
+/*
+  End tablespace part
+*/
 
 create2:
         '(' create2a {}
@@ -3192,6 +3595,9 @@
 	| INSERT_METHOD opt_equal merge_insert_types   { Lex->create_info.merge_insert_method= $3; Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;}
 	| DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.data_file_name= $4.str; Lex->create_info.used_fields|= HA_CREATE_USED_DATADIR; }
 	| INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.index_file_name= $4.str;  Lex->create_info.used_fields|= HA_CREATE_USED_INDEXDIR; }
+        | TABLESPACE ident {Lex->create_info.tablespace= $2.str;}
+        | STORAGE_SYM DISK_SYM {Lex->create_info.store_on_disk= TRUE;}
+        | STORAGE_SYM MEMORY_SYM {Lex->create_info.store_on_disk= FALSE;}
 	| CONNECTION_SYM opt_equal TEXT_STRING_sys { Lex->create_info.connect_string.str= $3.str; Lex->create_info.connect_string.length= $3.length;  Lex->create_info.used_fields|= HA_CREATE_USED_CONNECTION; }
         ;
 
@@ -3931,6 +4337,26 @@
 	  }
 	  opt_view_list AS select_view_init check_option
 	  {}
+        | ALTER TABLESPACE alter_tablespace_info
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_cmd_type= ALTER_TABLESPACE;
+          }
+        | ALTER LOGFILE_SYM GROUP alter_logfile_group_info 
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_cmd_type= ALTER_LOGFILE_GROUP;
+          }
+        | ALTER TABLESPACE change_tablespace_info
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_cmd_type= CHANGE_FILE_TABLESPACE;
+          }
+        | ALTER TABLESPACE change_tablespace_access 
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_cmd_type= ALTER_ACCESS_MODE_TABLESPACE;
+          }
 	;
 
 ident_or_empty:
@@ -6651,6 +7077,16 @@
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_DROP_TRIGGER;
             lex->spname= $3;
+	  }
+        | DROP TABLESPACE tablespace_name opt_ts_engine opt_ts_wait
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_cmd_type= DROP_TABLESPACE;
+          }
+        | DROP LOGFILE_SYM GROUP logfile_group_name opt_ts_engine opt_ts_wait
+          {
+            LEX *lex= Lex;
+            lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP;
           }
 	;
 
@@ -8152,6 +8588,7 @@
 	| ALGORITHM_SYM		{}
 	| ANY_SYM		{}
 	| AUTO_INC		{}
+        | AUTOEXTEND_SIZE_SYM   {}
 	| AVG_ROW_LENGTH	{}
 	| AVG_SYM		{}
 	| BERKELEY_DB_SYM	{}
@@ -8175,6 +8612,7 @@
 	| CONSISTENT_SYM	{}
 	| CUBE_SYM		{}
 	| DATA_SYM		{}
+        | DATAFILE_SYM          {}
 	| DATETIME		{}
 	| DATE_SYM		{}
 	| DAY_SYM		{}
@@ -8183,6 +8621,7 @@
 	| DES_KEY_FILE		{}
 	| DIRECTORY_SYM		{}
 	| DISCARD		{}
+        | DISK_SYM              {}
 	| DUMPFILE		{}
 	| DUPLICATE_SYM		{}
 	| DYNAMIC_SYM		{}
@@ -8194,6 +8633,7 @@
 	| EVENTS_SYM		{}
         | EXPANSION_SYM         {}
 	| EXTENDED_SYM		{}
+        | EXTENT_SIZE_SYM       {}
 	| FAST_SYM		{}
 	| FOUND_SYM		{}
 	| DISABLE_SYM		{}
@@ -8215,6 +8655,7 @@
 	| INVOKER_SYM		{}
 	| IMPORT		{}
 	| INDEXES		{}
+        | INITIAL_SIZE_SYM      {}
 	| ISOLATION		{}
 	| ISSUER_SYM		{}
 	| INNOBASE_SYM		{}
@@ -8228,6 +8669,7 @@
 	| LIST_SYM		{}
 	| LOCAL_SYM		{}
 	| LOCKS_SYM		{}
+        | LOGFILE_SYM           {}
 	| LOGS_SYM		{}
 	| MAX_ROWS		{}
 	| MASTER_SYM		{}
@@ -8247,10 +8689,12 @@
 	| MASTER_SSL_KEY_SYM	{}
 	| MAX_CONNECTIONS_PER_HOUR	 {}
 	| MAX_QUERIES_PER_HOUR	{}
+        | MAX_SIZE_SYM          {}
 	| MAX_UPDATES_PER_HOUR	{}
 	| MAX_USER_CONNECTIONS_SYM {}
 	| MAX_VALUE_SYM         {}
 	| MEDIUM_SYM		{}
+	| MEMORY_SYM		{}
 	| MERGE_SYM		{}
 	| MICROSECOND_SYM	{}
         | MIGRATE_SYM           {}
@@ -8270,7 +8714,8 @@
 	| NDBCLUSTER_SYM	{}
 	| NEXT_SYM		{}
 	| NEW_SYM		{}
-	| NODEGROUP_SYM		{}
+        | NO_WAIT_SYM           {}
+        | NODEGROUP_SYM         {}
 	| NONE_SYM		{}
 	| NVARCHAR_SYM		{}
 	| OFFSET_SYM		{}
@@ -8297,6 +8742,8 @@
 	| RAID_STRIPED_SYM	{}
 	| RAID_TYPE		{}
         | RECOVER_SYM           {}
+	| REDO_BUFFER_SIZE_SYM	{}
+	| REDOFILE_SYM  	{}
         | REDUNDANT_SYM         {}
 	| RELAY_LOG_FILE_SYM	{}
 	| RELAY_LOG_POS_SYM	{}
@@ -8353,6 +8800,8 @@
 	| FUNCTION_SYM		{}
 	| UNCOMMITTED_SYM	{}
 	| UNDEFINED_SYM		{}
+	| UNDO_BUFFER_SIZE_SYM	{}
+	| UNDOFILE_SYM  	{}
 	| UNKNOWN_SYM		{}
 	| UNTIL_SYM		{}
 	| USER			{}
@@ -8361,6 +8810,7 @@
 	| VIEW_SYM		{}
 	| VALUE_SYM		{}
 	| WARNINGS		{}
+        | WAIT_SYM              {}
 	| WEEK_SYM		{}
 	| WORK_SYM		{}
 	| X509_SYM		{}

--- 1.49/sql/share/errmsg.txt	2005-10-06 10:49:29 +02:00
+++ 1.50/sql/share/errmsg.txt	2005-10-10 20:32:20 +02:00
@@ -5539,3 +5539,17 @@
 ER_DROP_PARTITION_WHEN_FK_DEFINED
         eng "Cannot drop a partition when a foreign key constraint is defined on the table"
+ER_TABLESPACE_OPTION_ONLY_ONCE
+        eng "It is not allowed to specify %s more than once"
+ER_CREATE_TABLESPACE_FAILED
+        eng "Failed to create %s"
+ER_DROP_TABLESPACE_FAILED
+        eng "Failed to drop %s"
+ER_TABLESPACE_AUTO_EXTEND_ERROR
+        eng "The handler doesn't support autoextend of tablespaces"
+ER_WRONG_SIZE_NUMBER
+        eng "A size parameter was incorrectly specified, either number or on the form 10M"
+ER_SIZE_OVERFLOW_ERROR
+        eng "The size number was correct but we don't allow the digit part to be more than 2 billion"
+ER_ALTER_TABLESPACE_FAILED
+        eng "Failed to alter: %s"
--- New file ---
+++ mysql-test/r/ndb_basic_disk.result	05/10/10 21:27:14
DROP TABLE IF EXISTS t1;
CREATE LOGFILE GROUP lg1
ADD UNDOFILE 'undofile.dat'
INITIAL_SIZE 16M
UNDO_BUFFER_SIZE = 1M
ENGINE=NDB;
alter logfile group lg1
add undofile 'undofile02.dat'
initial_size 4M engine=ndb;
CREATE TABLESPACE ts1
ADD DATAFILE 'datafile.dat'
USE LOGFILE GROUP lg1
INITIAL_SIZE 12M
ENGINE NDB;
alter tablespace ts1
add datafile 'datafile02.dat'
initial_size 4M engine=ndb;
CREATE TABLE t1
(pk1 int not null primary key, b int not null, c int not null)
tablespace ts1 storage disk
engine ndb;
INSERT INTO t1 VALUES (0, 0, 0);
SELECT * FROM t1;
pk1	b	c
0	0	0
INSERT INTO t1 VALUES 
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10),
(11,11,11),(12,12,12),(13,13,13),(14,14,14),(15,15,15),
(16,16,16),(17,17,17),(18,18,18),(19,19,19),(20,20,20),
(21,21,21),(22,22,22),(23,23,23),(24,24,24),(25,25,25),
(26,26,26),(27,27,27),(28,28,28),(29,29,29),(30,30,30),
(31,31,31),(32,32,32),(33,33,33),(34,34,34),(35,35,35),
(36,36,36),(37,37,37),(38,38,38),(39,39,39),(40,40,40),
(41,41,41),(42,42,42),(43,43,43),(44,44,44),(45,45,45),
(46,46,46),(47,47,47),(48,48,48),(49,49,49),(50,50,50),
(51,51,51),(52,52,52),(53,53,53),(54,54,54),(55,55,55),
(56,56,56),(57,57,57),(58,58,58),(59,59,59),(60,60,60),
(61,61,61),(62,62,62),(63,63,63),(64,64,64),(65,65,65),
(66,66,66),(67,67,67),(68,68,68),(69,69,69),(70,70,70),
(71,71,71),(72,72,72),(73,73,73),(74,74,74),(75,75,75),
(76,76,76),(77,77,77),(78,78,78),(79,79,79),(80,80,80),
(81,81,81),(82,82,82),(83,83,83),(84,84,84),(85,85,85),
(86,86,86),(87,87,87),(88,88,88),(89,89,89),(90,90,90),
(91,91,91),(92,92,92),(93,93,93),(94,94,94),(95,95,95),
(96,96,96),(97,97,97),(98,98,98),(99,99,99),(100,100,100),
(101,101,101),(102,102,102),(103,103,103),(104,104,104),(105,105,105),
(106,106,106),(107,107,107),(108,108,108),(109,109,109),(110,110,110),
(111,111,111),(112,112,112),(113,113,113),(114,114,114),(115,115,115),
(116,116,116),(117,117,117),(118,118,118),(119,119,119),(120,120,120),
(121,121,121),(122,122,122),(123,123,123),(124,124,124),(125,125,125),
(126,126,126),(127,127,127),(128,128,128),(129,129,129),(130,130,130),
(131,131,131),(132,132,132),(133,133,133),(134,134,134),(135,135,135),
(136,136,136),(137,137,137),(138,138,138),(139,139,139),(140,140,140),
(141,141,141),(142,142,142),(143,143,143),(144,144,144),(145,145,145),
(146,146,146),(147,147,147),(148,148,148),(149,149,149),(150,150,150),
(151,151,151),(152,152,152),(153,153,153),(154,154,154),(155,155,155),
(156,156,156),(157,157,157),(158,158,158),(159,159,159),(160,160,160),
(161,161,161),(162,162,162),(163,163,163),(164,164,164),(165,165,165),
(166,166,166),(167,167,167),(168,168,168),(169,169,169),(170,170,170),
(171,171,171),(172,172,172),(173,173,173),(174,174,174),(175,175,175),
(176,176,176),(177,177,177),(178,178,178),(179,179,179),(180,180,180),
(181,181,181),(182,182,182),(183,183,183),(184,184,184),(185,185,185),
(186,186,186),(187,187,187),(188,188,188),(189,189,189),(190,190,190),
(191,191,191),(192,192,192),(193,193,193),(194,194,194),(195,195,195),
(196,196,196),(197,197,197),(198,198,198),(199,199,199),(200,200,200),
(201,201,201),(202,202,202),(203,203,203),(204,204,204),(205,205,205),
(206,206,206),(207,207,207),(208,208,208),(209,209,209),(210,210,210),
(211,211,211),(212,212,212),(213,213,213),(214,214,214),(215,215,215),
(216,216,216),(217,217,217),(218,218,218),(219,219,219),(220,220,220),
(221,221,221),(222,222,222),(223,223,223),(224,224,224),(225,225,225),
(226,226,226),(227,227,227),(228,228,228),(229,229,229),(230,230,230),
(231,231,231),(232,232,232),(233,233,233),(234,234,234),(235,235,235),
(236,236,236),(237,237,237),(238,238,238),(239,239,239),(240,240,240),
(241,241,241),(242,242,242),(243,243,243),(244,244,244),(245,245,245),
(246,246,246),(247,247,247),(248,248,248),(249,249,249),(250,250,250),
(251,251,251),(252,252,252),(253,253,253),(254,254,254),(255,255,255),
(256,256,256),(257,257,257),(258,258,258),(259,259,259),(260,260,260),
(261,261,261),(262,262,262),(263,263,263),(264,264,264),(265,265,265),
(266,266,266),(267,267,267),(268,268,268),(269,269,269),(270,270,270),
(271,271,271),(272,272,272),(273,273,273),(274,274,274),(275,275,275),
(276,276,276),(277,277,277),(278,278,278),(279,279,279),(280,280,280),
(281,281,281),(282,282,282),(283,283,283),(284,284,284),(285,285,285),
(286,286,286),(287,287,287),(288,288,288),(289,289,289),(290,290,290),
(291,291,291),(292,292,292),(293,293,293),(294,294,294),(295,295,295),
(296,296,296),(297,297,297),(298,298,298),(299,299,299),(300,300,300),
(301,301,301),(302,302,302),(303,303,303),(304,304,304),(305,305,305),
(306,306,306),(307,307,307),(308,308,308),(309,309,309),(310,310,310),
(311,311,311),(312,312,312),(313,313,313),(314,314,314),(315,315,315),
(316,316,316),(317,317,317),(318,318,318),(319,319,319),(320,320,320),
(321,321,321),(322,322,322),(323,323,323),(324,324,324),(325,325,325),
(326,326,326),(327,327,327),(328,328,328),(329,329,329),(330,330,330),
(331,331,331),(332,332,332),(333,333,333),(334,334,334),(335,335,335),
(336,336,336),(337,337,337),(338,338,338),(339,339,339),(340,340,340),
(341,341,341),(342,342,342),(343,343,343),(344,344,344),(345,345,345),
(346,346,346),(347,347,347),(348,348,348),(349,349,349),(350,350,350),
(351,351,351),(352,352,352),(353,353,353),(354,354,354),(355,355,355),
(356,356,356),(357,357,357),(358,358,358),(359,359,359),(360,360,360),
(361,361,361),(362,362,362),(363,363,363),(364,364,364),(365,365,365),
(366,366,366),(367,367,367),(368,368,368),(369,369,369),(370,370,370),
(371,371,371),(372,372,372),(373,373,373),(374,374,374),(375,375,375),
(376,376,376),(377,377,377),(378,378,378),(379,379,379),(380,380,380),
(381,381,381),(382,382,382),(383,383,383),(384,384,384),(385,385,385),
(386,386,386),(387,387,387),(388,388,388),(389,389,389),(390,390,390),
(391,391,391),(392,392,392),(393,393,393),(394,394,394),(395,395,395),
(396,396,396),(397,397,397),(398,398,398),(399,399,399),(400,400,400),
(401,401,401),(402,402,402),(403,403,403),(404,404,404),(405,405,405),
(406,406,406),(407,407,407),(408,408,408),(409,409,409),(410,410,410),
(411,411,411),(412,412,412),(413,413,413),(414,414,414),(415,415,415),
(416,416,416),(417,417,417),(418,418,418),(419,419,419),(420,420,420),
(421,421,421),(422,422,422),(423,423,423),(424,424,424),(425,425,425),
(426,426,426),(427,427,427),(428,428,428),(429,429,429),(430,430,430),
(431,431,431),(432,432,432),(433,433,433),(434,434,434),(435,435,435),
(436,436,436),(437,437,437),(438,438,438),(439,439,439),(440,440,440),
(441,441,441),(442,442,442),(443,443,443),(444,444,444),(445,445,445),
(446,446,446),(447,447,447),(448,448,448),(449,449,449),(450,450,450),
(451,451,451),(452,452,452),(453,453,453),(454,454,454),(455,455,455),
(456,456,456),(457,457,457),(458,458,458),(459,459,459),(460,460,460),
(461,461,461),(462,462,462),(463,463,463),(464,464,464),(465,465,465),
(466,466,466),(467,467,467),(468,468,468),(469,469,469),(470,470,470),
(471,471,471),(472,472,472),(473,473,473),(474,474,474),(475,475,475),
(476,476,476),(477,477,477),(478,478,478),(479,479,479),(480,480,480),
(481,481,481),(482,482,482),(483,483,483),(484,484,484),(485,485,485),
(486,486,486),(487,487,487),(488,488,488),(489,489,489),(490,490,490),
(491,491,491),(492,492,492),(493,493,493),(494,494,494),(495,495,495),
(496,496,496),(497,497,497),(498,498,498),(499,499,499),(500, 500, 500);
SELECT COUNT(*) FROM t1;
COUNT(*)
501
CREATE LOGFILE GROUP lg2
ADD UNDOFILE 'x.dat'
INITIAL_SIZE 10y
engine = ndb;
ERROR HY000: A size parameter was incorrectly specified, either number or on the form 10M
CREATE LOGFILE GROUP lg2
ADD UNDOFILE 'x.dat'
INITIAL_SIZE 10MB
engine=ndb;
ERROR HY000: A size parameter was incorrectly specified, either number or on the form 10M
CREATE LOGFILE GROUP lg2
ADD UNDOFILE 'x.dat'
INITIAL_SIZE 10 MB
engine=ndb;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'MB
engine=ndb' at line 3
CREATE LOGFILE GROUP lg2
ADD UNDOFILE 'x.dat'
INITIAL_SIZE 10 M
engine=ndb;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'M
engine=ndb' at line 3
CREATE LOGFILE GROUP lg2
ADD UNDOFILE 'x.dat'
INITIAL_SIZE 1000000000000K
engine=ndb;
ERROR HY000: The size number was correct but we don't allow the digit part to be more than 2 billion
DROP TABLE t1;
create table t1 (a int primary key, b char(4) not null, c char(4) not null, key(b)) tablespace ts1 storage disk engine ndb;
insert into t1 values (1,'1','1'), (2,'2','2'), (3,'3','3');
begin;
update t1 set b = '2' where a = 1;
select b from t1 where a = 1;
b
2
select * from t1 where a = 1;
a	b	c
1	2	1
update t1 set c = '2' where a = 1;
select b from t1 where a = 1;
b
2
select * from t1 where a = 1;
a	b	c
1	2	2
update t1 set b = '3' where a = 1;
select b from t1 where a = 1;
b
3
select * from t1 where a = 1;
a	b	c
1	3	2
commit;
select * from t1 order by 1;
a	b	c
1	3	2
2	2	2
3	3	3
begin;
update t1 set c = '3' where a = 1;
select b from t1 where a = 1;
b
3
select * from t1 where a = 1;
a	b	c
1	3	3
update t1 set b = '4' where a = 1;
select b from t1 where a = 1;
b
4
select * from t1 where a = 1;
a	b	c
1	4	3
update t1 set c = '4' where a = 1;
select b from t1 where a = 1;
b
4
select * from t1 where a = 1;
a	b	c
1	4	4
commit;
select * from t1 order by 1;
a	b	c
1	4	4
2	2	2
3	3	3
update t1 set b = '5' where a = 1;
select * from t1 order by 1;
a	b	c
1	5	4
2	2	2
3	3	3
update t1 set b = '6'  where b = '5';
select * from t1 order by 1;
a	b	c
1	6	4
2	2	2
3	3	3
update t1 set b = '7'  where c = '4';
select * from t1 order by 1;
a	b	c
1	7	4
2	2	2
3	3	3
update t1 set c = '5' where a = 1;
select * from t1 order by 1;
a	b	c
1	7	5
2	2	2
3	3	3
update t1 set c = '6'  where b = '7';
select * from t1 order by 1;
a	b	c
1	7	6
2	2	2
3	3	3
update t1 set c = '7'  where c = '6';
select * from t1 order by 1;
a	b	c
1	7	7
2	2	2
3	3	3
drop table t1;
create table t1 (a int primary key, b varchar(4) not null, c char(4) not null, key(b)) tablespace ts1 storage disk engine ndb;
insert into t1 values (1,'1','1'), (2,'2','2'), (3,'3','3');
begin;
update t1 set b = '2' where a = 1;
select b from t1 where a = 1;
b
2
select * from t1 where a = 1;
a	b	c
1	2	1
update t1 set c = '2' where a = 1;
select b from t1 where a = 1;
b
2
select * from t1 where a = 1;
a	b	c
1	2	2
update t1 set b = '3' where a = 1;
select b from t1 where a = 1;
b
3
select * from t1 where a = 1;
a	b	c
1	3	2
commit;
select * from t1 order by 1;
a	b	c
1	3	2
2	2	2
3	3	3
begin;
update t1 set c = '3' where a = 1;
select b from t1 where a = 1;
b
3
select * from t1 where a = 1;
a	b	c
1	3	3
update t1 set b = '4' where a = 1;
select b from t1 where a = 1;
b
4
select * from t1 where a = 1;
a	b	c
1	4	3
update t1 set c = '4' where a = 1;
select b from t1 where a = 1;
b
4
select * from t1 where a = 1;
a	b	c
1	4	4
commit;
select * from t1 order by 1;
a	b	c
1	4	4
2	2	2
3	3	3
update t1 set b = '5' where a = 1;
select * from t1 order by 1;
a	b	c
1	5	4
2	2	2
3	3	3
update t1 set b = '6'  where b = '5';
select * from t1 order by 1;
a	b	c
1	6	4
2	2	2
3	3	3
update t1 set b = '7'  where c = '4';
select * from t1 order by 1;
a	b	c
1	7	4
2	2	2
3	3	3
update t1 set c = '5' where a = 1;
select * from t1 order by 1;
a	b	c
1	7	5
2	2	2
3	3	3
update t1 set c = '6'  where b = '7';
select * from t1 order by 1;
a	b	c
1	7	6
2	2	2
3	3	3
update t1 set c = '7'  where c = '6';
select * from t1 order by 1;
a	b	c
1	7	7
2	2	2
3	3	3
drop table t1;
alter tablespace ts1 drop datafile 'datafile.dat' engine = ndb;
alter tablespace ts1 drop datafile 'datafile02.dat' engine = ndb;
drop tablespace ts1 engine = ndb;
drop logfile group lg1 engine = ndb;

--- New file ---
+++ mysql-test/t/ndb_basic_disk.test	05/10/10 21:27:14
-- source include/have_ndb.inc

--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings

#
# Basic test of disk tables for NDB
#

#
# Start by creating a logfile group
#

CREATE LOGFILE GROUP lg1
ADD UNDOFILE 'undofile.dat'
INITIAL_SIZE 16M
UNDO_BUFFER_SIZE = 1M
ENGINE=NDB;

alter logfile group lg1
add undofile 'undofile02.dat'
initial_size 4M engine=ndb;

#
# Create a tablespace connected to the logfile group
#

CREATE TABLESPACE ts1
ADD DATAFILE 'datafile.dat'
USE LOGFILE GROUP lg1
INITIAL_SIZE 12M
ENGINE NDB;

alter tablespace ts1
add datafile 'datafile02.dat'
initial_size 4M engine=ndb;

#
# Create a table using this tablespace
#

CREATE TABLE t1
(pk1 int not null primary key, b int not null, c int not null)
tablespace ts1 storage disk
engine ndb;

INSERT INTO t1 VALUES (0, 0, 0);
SELECT * FROM t1;

INSERT INTO t1 VALUES 
(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10),
(11,11,11),(12,12,12),(13,13,13),(14,14,14),(15,15,15),
(16,16,16),(17,17,17),(18,18,18),(19,19,19),(20,20,20),
(21,21,21),(22,22,22),(23,23,23),(24,24,24),(25,25,25),
(26,26,26),(27,27,27),(28,28,28),(29,29,29),(30,30,30),
(31,31,31),(32,32,32),(33,33,33),(34,34,34),(35,35,35),
(36,36,36),(37,37,37),(38,38,38),(39,39,39),(40,40,40),
(41,41,41),(42,42,42),(43,43,43),(44,44,44),(45,45,45),
(46,46,46),(47,47,47),(48,48,48),(49,49,49),(50,50,50),
(51,51,51),(52,52,52),(53,53,53),(54,54,54),(55,55,55),
(56,56,56),(57,57,57),(58,58,58),(59,59,59),(60,60,60),
(61,61,61),(62,62,62),(63,63,63),(64,64,64),(65,65,65),
(66,66,66),(67,67,67),(68,68,68),(69,69,69),(70,70,70),
(71,71,71),(72,72,72),(73,73,73),(74,74,74),(75,75,75),
(76,76,76),(77,77,77),(78,78,78),(79,79,79),(80,80,80),
(81,81,81),(82,82,82),(83,83,83),(84,84,84),(85,85,85),
(86,86,86),(87,87,87),(88,88,88),(89,89,89),(90,90,90),
(91,91,91),(92,92,92),(93,93,93),(94,94,94),(95,95,95),
(96,96,96),(97,97,97),(98,98,98),(99,99,99),(100,100,100),
(101,101,101),(102,102,102),(103,103,103),(104,104,104),(105,105,105),
(106,106,106),(107,107,107),(108,108,108),(109,109,109),(110,110,110),
(111,111,111),(112,112,112),(113,113,113),(114,114,114),(115,115,115),
(116,116,116),(117,117,117),(118,118,118),(119,119,119),(120,120,120),
(121,121,121),(122,122,122),(123,123,123),(124,124,124),(125,125,125),
(126,126,126),(127,127,127),(128,128,128),(129,129,129),(130,130,130),
(131,131,131),(132,132,132),(133,133,133),(134,134,134),(135,135,135),
(136,136,136),(137,137,137),(138,138,138),(139,139,139),(140,140,140),
(141,141,141),(142,142,142),(143,143,143),(144,144,144),(145,145,145),
(146,146,146),(147,147,147),(148,148,148),(149,149,149),(150,150,150),
(151,151,151),(152,152,152),(153,153,153),(154,154,154),(155,155,155),
(156,156,156),(157,157,157),(158,158,158),(159,159,159),(160,160,160),
(161,161,161),(162,162,162),(163,163,163),(164,164,164),(165,165,165),
(166,166,166),(167,167,167),(168,168,168),(169,169,169),(170,170,170),
(171,171,171),(172,172,172),(173,173,173),(174,174,174),(175,175,175),
(176,176,176),(177,177,177),(178,178,178),(179,179,179),(180,180,180),
(181,181,181),(182,182,182),(183,183,183),(184,184,184),(185,185,185),
(186,186,186),(187,187,187),(188,188,188),(189,189,189),(190,190,190),
(191,191,191),(192,192,192),(193,193,193),(194,194,194),(195,195,195),
(196,196,196),(197,197,197),(198,198,198),(199,199,199),(200,200,200),
(201,201,201),(202,202,202),(203,203,203),(204,204,204),(205,205,205),
(206,206,206),(207,207,207),(208,208,208),(209,209,209),(210,210,210),
(211,211,211),(212,212,212),(213,213,213),(214,214,214),(215,215,215),
(216,216,216),(217,217,217),(218,218,218),(219,219,219),(220,220,220),
(221,221,221),(222,222,222),(223,223,223),(224,224,224),(225,225,225),
(226,226,226),(227,227,227),(228,228,228),(229,229,229),(230,230,230),
(231,231,231),(232,232,232),(233,233,233),(234,234,234),(235,235,235),
(236,236,236),(237,237,237),(238,238,238),(239,239,239),(240,240,240),
(241,241,241),(242,242,242),(243,243,243),(244,244,244),(245,245,245),
(246,246,246),(247,247,247),(248,248,248),(249,249,249),(250,250,250),
(251,251,251),(252,252,252),(253,253,253),(254,254,254),(255,255,255),
(256,256,256),(257,257,257),(258,258,258),(259,259,259),(260,260,260),
(261,261,261),(262,262,262),(263,263,263),(264,264,264),(265,265,265),
(266,266,266),(267,267,267),(268,268,268),(269,269,269),(270,270,270),
(271,271,271),(272,272,272),(273,273,273),(274,274,274),(275,275,275),
(276,276,276),(277,277,277),(278,278,278),(279,279,279),(280,280,280),
(281,281,281),(282,282,282),(283,283,283),(284,284,284),(285,285,285),
(286,286,286),(287,287,287),(288,288,288),(289,289,289),(290,290,290),
(291,291,291),(292,292,292),(293,293,293),(294,294,294),(295,295,295),
(296,296,296),(297,297,297),(298,298,298),(299,299,299),(300,300,300),
(301,301,301),(302,302,302),(303,303,303),(304,304,304),(305,305,305),
(306,306,306),(307,307,307),(308,308,308),(309,309,309),(310,310,310),
(311,311,311),(312,312,312),(313,313,313),(314,314,314),(315,315,315),
(316,316,316),(317,317,317),(318,318,318),(319,319,319),(320,320,320),
(321,321,321),(322,322,322),(323,323,323),(324,324,324),(325,325,325),
(326,326,326),(327,327,327),(328,328,328),(329,329,329),(330,330,330),
(331,331,331),(332,332,332),(333,333,333),(334,334,334),(335,335,335),
(336,336,336),(337,337,337),(338,338,338),(339,339,339),(340,340,340),
(341,341,341),(342,342,342),(343,343,343),(344,344,344),(345,345,345),
(346,346,346),(347,347,347),(348,348,348),(349,349,349),(350,350,350),
(351,351,351),(352,352,352),(353,353,353),(354,354,354),(355,355,355),
(356,356,356),(357,357,357),(358,358,358),(359,359,359),(360,360,360),
(361,361,361),(362,362,362),(363,363,363),(364,364,364),(365,365,365),
(366,366,366),(367,367,367),(368,368,368),(369,369,369),(370,370,370),
(371,371,371),(372,372,372),(373,373,373),(374,374,374),(375,375,375),
(376,376,376),(377,377,377),(378,378,378),(379,379,379),(380,380,380),
(381,381,381),(382,382,382),(383,383,383),(384,384,384),(385,385,385),
(386,386,386),(387,387,387),(388,388,388),(389,389,389),(390,390,390),
(391,391,391),(392,392,392),(393,393,393),(394,394,394),(395,395,395),
(396,396,396),(397,397,397),(398,398,398),(399,399,399),(400,400,400),
(401,401,401),(402,402,402),(403,403,403),(404,404,404),(405,405,405),
(406,406,406),(407,407,407),(408,408,408),(409,409,409),(410,410,410),
(411,411,411),(412,412,412),(413,413,413),(414,414,414),(415,415,415),
(416,416,416),(417,417,417),(418,418,418),(419,419,419),(420,420,420),
(421,421,421),(422,422,422),(423,423,423),(424,424,424),(425,425,425),
(426,426,426),(427,427,427),(428,428,428),(429,429,429),(430,430,430),
(431,431,431),(432,432,432),(433,433,433),(434,434,434),(435,435,435),
(436,436,436),(437,437,437),(438,438,438),(439,439,439),(440,440,440),
(441,441,441),(442,442,442),(443,443,443),(444,444,444),(445,445,445),
(446,446,446),(447,447,447),(448,448,448),(449,449,449),(450,450,450),
(451,451,451),(452,452,452),(453,453,453),(454,454,454),(455,455,455),
(456,456,456),(457,457,457),(458,458,458),(459,459,459),(460,460,460),
(461,461,461),(462,462,462),(463,463,463),(464,464,464),(465,465,465),
(466,466,466),(467,467,467),(468,468,468),(469,469,469),(470,470,470),
(471,471,471),(472,472,472),(473,473,473),(474,474,474),(475,475,475),
(476,476,476),(477,477,477),(478,478,478),(479,479,479),(480,480,480),
(481,481,481),(482,482,482),(483,483,483),(484,484,484),(485,485,485),
(486,486,486),(487,487,487),(488,488,488),(489,489,489),(490,490,490),
(491,491,491),(492,492,492),(493,493,493),(494,494,494),(495,495,495),
(496,496,496),(497,497,497),(498,498,498),(499,499,499),(500, 500, 500);

SELECT COUNT(*) FROM t1;

#
# Test error cases with size numbers
#
--error ER_WRONG_SIZE_NUMBER
CREATE LOGFILE GROUP lg2
ADD UNDOFILE 'x.dat'
INITIAL_SIZE 10y
engine = ndb;

--error ER_WRONG_SIZE_NUMBER
CREATE LOGFILE GROUP lg2
ADD UNDOFILE 'x.dat'
INITIAL_SIZE 10MB
engine=ndb;

--error 1064
CREATE LOGFILE GROUP lg2
ADD UNDOFILE 'x.dat'
INITIAL_SIZE 10 MB
engine=ndb;

--error 1064
CREATE LOGFILE GROUP lg2
ADD UNDOFILE 'x.dat'
INITIAL_SIZE 10 M
engine=ndb;

--error ER_SIZE_OVERFLOW_ERROR
CREATE LOGFILE GROUP lg2
ADD UNDOFILE 'x.dat'
INITIAL_SIZE 1000000000000K
engine=ndb;

DROP TABLE t1;

# Test update of mm/dd part
create table t1 (a int primary key, b char(4) not null, c char(4) not null, key(b)) tablespace ts1 storage disk engine ndb;
insert into t1 values (1,'1','1'), (2,'2','2'), (3,'3','3');
begin;
update t1 set b = '2' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
update t1 set c = '2' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
update t1 set b = '3' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
commit;
select * from t1 order by 1;
begin;
update t1 set c = '3' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
update t1 set b = '4' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
update t1 set c = '4' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
commit;
select * from t1 order by 1;
update t1 set b = '5' where a = 1;
select * from t1 order by 1;
update t1 set b = '6'  where b = '5';
select * from t1 order by 1;
update t1 set b = '7'  where c = '4';
select * from t1 order by 1;
update t1 set c = '5' where a = 1;
select * from t1 order by 1;
update t1 set c = '6'  where b = '7';
select * from t1 order by 1;
update t1 set c = '7'  where c = '6';
select * from t1 order by 1;
drop table t1;
create table t1 (a int primary key, b varchar(4) not null, c char(4) not null, key(b)) tablespace ts1 storage disk engine ndb;
insert into t1 values (1,'1','1'), (2,'2','2'), (3,'3','3');
begin;
update t1 set b = '2' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
update t1 set c = '2' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
update t1 set b = '3' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
commit;
select * from t1 order by 1;
begin;
update t1 set c = '3' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
update t1 set b = '4' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
update t1 set c = '4' where a = 1;
select b from t1 where a = 1;
select * from t1 where a = 1;
commit;
select * from t1 order by 1;
update t1 set b = '5' where a = 1;
select * from t1 order by 1;
update t1 set b = '6'  where b = '5';
select * from t1 order by 1;
update t1 set b = '7'  where c = '4';
select * from t1 order by 1;
update t1 set c = '5' where a = 1;
select * from t1 order by 1;
update t1 set c = '6'  where b = '7';
select * from t1 order by 1;
update t1 set c = '7'  where c = '6';
select * from t1 order by 1;
drop table t1;

alter tablespace ts1 drop datafile 'datafile.dat' engine = ndb;
alter tablespace ts1 drop datafile 'datafile02.dat' engine = ndb;
drop tablespace ts1 engine = ndb;

drop logfile group lg1 engine = ndb;


--- 1.2/storage/ndb/src/kernel/vm/KeyDescriptor.hpp	2005-08-25 20:51:23 +02:00
+++ 1.3/storage/ndb/src/kernel/vm/KeyDescriptor.hpp	2005-10-10 20:32:22 +02:00
@@ -23,12 +23,14 @@
 
 struct KeyDescriptor
 {
-  KeyDescriptor () { noOfKeyAttr = hasCharAttr = noOfDistrKeys = 0; }
+  KeyDescriptor () { 
+    noOfKeyAttr = hasCharAttr = noOfDistrKeys = noOfVarKeys = 0; 
+  }
   
   Uint8 noOfKeyAttr;
   Uint8 hasCharAttr;
   Uint8 noOfDistrKeys;
-  Uint8 unused;
+  Uint8 noOfVarKeys;
   struct KeyAttr 
   {
     Uint32 attributeDescriptor;
--- New file ---
+++ sql/sql_tablespace.cc	05/10/10 21:27:14
/* Copyright (C) 2000-2004 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* drop and alter of tablespaces */

#include "mysql_priv.h"

int mysql_alter_tablespace(st_alter_tablespace *ts_info)
{
  int error;
  handler *file;
  DBUG_ENTER("mysql_alter_tablespace");
  /*
    If the user haven't defined an engine, this will fallback to using the
    default storage engine.
  */
  if (!(file= get_new_handler((TABLE*) 0, ts_info->storage_engine)))
  {
    my_error(ER_OUTOFMEMORY, MYF(0), 128);
    DBUG_RETURN(1);
  }
  if (error= file->alter_tablespace(ts_info))
  {
    if (error == HA_ADMIN_NOT_IMPLEMENTED)
    {
      my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "");
    }
    else if (error == 1)
    {
      DBUG_RETURN(1);
    }
    else
    {
      my_error(error, MYF(0));
    }
    DBUG_RETURN(error);
  }
  DBUG_RETURN(FALSE);
}

--- New file ---
+++ storage/ndb/include/kernel/signaldata/CreateFilegroup.hpp	05/10/10 21:27:15
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef CREATE_FILEGROUP_HPP
#define CREATE_FILEGROUP_HPP

#include "SignalData.hpp"

struct CreateFilegroupReq {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class NdbDictInterface;
  friend class Dbdict;

  /**
   * For printing
   */
  friend bool printCREATE_FILEGROUP_REQ(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 3 );
  
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 objType;
  SECTION( FILEGROUP_INFO = 0 );
};

struct CreateFilegroupRef {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  
  /**
   * Sender(s) / Reciver(s)
   */
  friend class NdbDictInterface;
  
  /**
   * For printing
   */
  friend bool printCREATE_FILEGROUP_REF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 7 );

  enum ErrorCode {
    NoError = 0,
    Busy = 701,
    NotMaster = 702,
    NoMoreObjectRecords = 710,
    InvalidFormat = 740,
    OutOfFilegroupRecords = 765,
    InvalidExtentSize = 764,
    InvalidUndoBufferSize = 763,
    NoSuchLogfileGroup = 767,
    InvalidFilegroupVersion = 768
  };
  
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 masterNodeId;
  Uint32 errorCode;
  Uint32 errorLine; 
  Uint32 errorKey;
  Uint32 status;
};

struct CreateFilegroupConf {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  
  /**
   * Sender(s) / Reciver(s)
   */
  friend class NdbDictInterface;
  
  /**
   * For printing
   */
  friend bool printCREATE_FILEGROUP_CONF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 4 );

  Uint32 senderData;
  Uint32 senderRef;
  Uint32 filegroupId;
  Uint32 filegroupVersion;
};

struct CreateFileReq {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class NdbDictInterface;
  friend class Dbdict;
  friend class Tsman;

  /**
   * For printing
   */
  friend bool printCREATE_FILE_REQ(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 4 );
  
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 objType;
  Uint32 requestInfo;
  
  enum RequstInfo 
  {
    ForceCreateFile = 0x1
  };
  
  SECTION( FILE_INFO = 0 );
};

struct CreateFileRef {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  
  /**
   * Sender(s) / Reciver(s)
   */
  friend class NdbDictInterface;
  
  /**
   * For printing
   */
  friend bool printCREATE_FILE_REF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 7 );

  enum ErrorCode {
    NoError = 0,
    Busy = 701,
    NotMaster = 702,
    NoMoreObjectRecords = 710,
    InvalidFormat = 752,
    NoSuchFilegroup = 753,
    InvalidFilegroupVersion = 754,
    FilenameAlreadyExists = 760,
    OutOfFileRecords = 751,
    InvalidFileType = 750
  };
  
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 masterNodeId;
  Uint32 errorCode;
  Uint32 errorLine; 
  Uint32 errorKey;
  Uint32 status;
};

struct CreateFileConf {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Ndbcntr;
  friend class NdbDictInterface;
  
  /**
   * For printing
   */
  friend bool printCREATE_FILE_CONF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 4 );

  Uint32 senderData;
  Uint32 senderRef;
  Uint32 fileId;
};

#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp	05/10/10 21:27:15
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef CREATE_FILEGROUP_IMPL_HPP
#define CREATE_FILEGROUP_IMPL_HPP

#include "SignalData.hpp"

struct CreateFilegroupImplReq {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;

  /**
   * For printing
   */
  friend bool printCREATE_FILEGROUP_IMPL_REQ(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( TablespaceLength = 6 );
  STATIC_CONST( LogfileGroupLength = 5 );
  
  Uint32 senderData;
  Uint32 senderRef;  
  Uint32 filegroup_id;
  Uint32 filegroup_version;
  
  union {
    struct {
      Uint32 extent_size;
      Uint32 logfile_group_id;
    } tablespace;
    struct {
      Uint32 buffer_size; // In pages
    } logfile_group;
  };
};

struct CreateFilegroupImplRef {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;
  
  /**
   * For printing
   */
  friend bool printCREATE_FILEGROUP_IMPL_REF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 3 );

  enum ErrorCode {
    NoError = 0,
    FilegroupAlreadyExists = 1,
    OutOfFilegroupRecords = 2,
    OutOfLogBufferMemory = 3
  };
  
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 errorCode;
};

struct CreateFilegroupImplConf {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;
  
  /**
   * For printing
   */
  friend bool printCREATE_FILEGROUP_IMPL_CONF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 2 );

  Uint32 senderData;
  Uint32 senderRef;
};

struct CreateFileImplReq {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;

  /**
   * For printing
   */
  friend bool printCREATE_FILE_IMPL_REQ(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( DatafileLength = 9 );
  STATIC_CONST( UndofileLength = 8 );
  STATIC_CONST( CommitLength = 6 );
  STATIC_CONST( AbortLength = 6 );
  SECTION( FILENAME = 0 );
  
  enum RequestInfo {
    Create = 0x1,
    CreateForce = 0x2,
    Open = 0x4,
    Commit = 0x8,
    Abort = 0x10
  };
  
  Uint32 senderData;
  Uint32 senderRef;

  Uint32 requestInfo;
  Uint32 file_id;
  Uint32 filegroup_id;
  Uint32 filegroup_version;
  Uint32 file_size_hi;
  Uint32 file_size_lo;

  union {
    struct {
      Uint32 extent_size;
    } tablespace;
  };
};

struct CreateFileImplRef {
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;
  
  /**
   * For printing
   */
  friend bool printCREATE_FILE_IMPL_REF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 5 );

  enum ErrorCode {
    NoError = 0,
    InvalidFilegroup = 1,
    InvalidFilegroupVersion = 2,
    FileNoAlreadyExists = 3,
    OutOfFileRecords = 4,
    FileError = 5,
    InvalidFileMetadata = 6,
    OutOfMemory = 7,
    FileReadError = 8,
    FilegroupNotOnline = 9
  };
  
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 errorCode;
  Uint32 fsErrCode;
  Uint32 osErrCode;
};

struct CreateFileImplConf {
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;
  
  
  /**
   * For printing
   */
  friend bool printCREATE_FILE_IMPL_CONF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 4 );

  Uint32 senderData;
  Uint32 senderRef;
};

#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/CreateObj.hpp	05/10/10 21:27:15
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef CREATE_OBJ_HPP
#define CREATE_OBJ_HPP

#include "DictObjOp.hpp"
#include "SignalData.hpp"

/**
 * CreateObj
 *
 * Implemenatation of CreateObj
 */
struct CreateObjReq {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Dbdict;

  /**
   * For printing
   */
  friend bool printCREATE_OBJ_REQ(FILE*, const Uint32*, Uint32, Uint16);
  
public:
  STATIC_CONST( SignalLength = 10 );
  STATIC_CONST( GSN = GSN_CREATE_OBJ_REQ );
  
private:
  Uint32 op_key;
  Uint32 senderRef;
  Uint32 senderData;
  Uint32 requestInfo;

  Uint32 clientRef;
  Uint32 clientData;

  Uint32 objId;
  Uint32 objType;
  Uint32 objVersion;
  Uint32 gci;

  SECTION( DICT_OBJ_INFO = 0 );
};

struct CreateObjRef {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Dbdict;
  friend class SafeCounter;
  
  /**
   * For printing
   */
  friend bool printCREATE_OBJ_REF(FILE *, const Uint32 *, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 6 );
  STATIC_CONST( GSN = GSN_CREATE_OBJ_REF );

  enum ErrorCode {
    NF_FakeErrorREF = 255
  };


  Uint32 senderRef;
  Uint32 senderData;
  Uint32 errorCode;
  Uint32 errorLine; 
  Uint32 errorKey;
  Uint32 errorStatus;
};

struct CreateObjConf {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Dbdict;
  
  /**
   * For printing
   */
  friend bool printCREATE_OBJ_CONF(FILE *, const Uint32 *, Uint32, Uint16);
  
public:
  STATIC_CONST( SignalLength = 2 );

private:
  Uint32 senderRef;
  Uint32 senderData;
};

#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/DictObjOp.hpp	05/10/10 21:27:15
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef DICT_OBJ_OP_HPP
#define DICT_OBJ_OP_HPP

struct DictObjOp {
  
  enum RequestType {
    Prepare = 0, // Prepare create obj
    Commit = 1,  // Commit create obj
    Abort = 2    // Prepare failed, drop instead
  };
  
  enum State {
    Defined = 0,
    Preparing = 1,
    Prepared = 2,
    Committing = 3,
    Committed = 4,
    Aborting = 5,
    Aborted = 6
  };
};

struct DictCommitReq
{
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 op_key;

  STATIC_CONST( SignalLength = 3 );
  STATIC_CONST( GSN = GSN_DICT_COMMIT_REQ );
};

struct DictCommitRef
{
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 errorCode;
  enum ErrorCode 
  {
    NF_FakeErrorREF = 1
  };
  STATIC_CONST( SignalLength = 3 );
  STATIC_CONST( GSN = GSN_DICT_COMMIT_REF );
};

struct DictCommitConf
{
  Uint32 senderData;
  Uint32 senderRef;

  STATIC_CONST( SignalLength = 2 );
  STATIC_CONST( GSN = GSN_DICT_COMMIT_CONF );
};

struct DictAbortReq
{
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 op_key;

  STATIC_CONST( SignalLength = 3 );
  STATIC_CONST( GSN = GSN_DICT_ABORT_REQ );
};

struct DictAbortRef
{
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 errorCode;
  enum ErrorCode 
  {
    NF_FakeErrorREF = 1
  };
  STATIC_CONST( SignalLength = 3 );
  STATIC_CONST( GSN = GSN_DICT_ABORT_REF );
};

struct DictAbortConf
{
  Uint32 senderData;
  Uint32 senderRef;

  STATIC_CONST( SignalLength = 2 );
  STATIC_CONST( GSN = GSN_DICT_ABORT_CONF );
};


#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/DropFilegroup.hpp	05/10/10 21:27:16
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef DROP_FILEGROUP_HPP
#define DROP_FILEGROUP_HPP

#include "SignalData.hpp"

struct DropFilegroupReq {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class NdbDictInterface;
  friend class Dbdict;
  friend class Tsman;

  /**
   * For printing
   */
  friend bool printDROP_FILEGROUP_REQ(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 4 );
  STATIC_CONST( GSN = GSN_DROP_FILEGROUP_REQ );
  
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 filegroup_id;
  Uint32 filegroup_version;
};

struct DropFilegroupRef {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Ndbcntr;
  friend class NdbDictInterface;
  
  /**
   * For printing
   */
  friend bool printDROP_FILEGROUP_REF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 7 );
  STATIC_CONST( GSN = GSN_DROP_FILEGROUP_REF );

  enum ErrorCode {
    NoError = 0,
    Busy = 701,
    NotMaster = 702,
    NoSuchFilegroup = 767,
    FilegroupInUse = 768
  };

  Uint32 senderData;
  Uint32 senderRef;
  Uint32 masterNodeId;
  Uint32 errorCode;
  Uint32 errorLine; 
  Uint32 errorKey;

};

struct DropFilegroupConf {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Ndbcntr;
  friend class NdbDictInterface;
  
  /**
   * For printing
   */
  friend bool printDROP_FILEGROUP_CONF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 4 );
  STATIC_CONST( GSN = GSN_DROP_FILEGROUP_CONF );

  Uint32 senderData;
  Uint32 senderRef;
  Uint32 filegroupId;
  Uint32 filegroupVersion;
};

struct DropFileReq {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class NdbDictInterface;
  friend class Dbdict;
  friend class Tsman;

  /**
   * For printing
   */
  friend bool printDROP_FILE_REQ(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 4 );
  STATIC_CONST( GSN = GSN_DROP_FILE_REQ );
  
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 file_id;
  Uint32 file_version;
};

struct DropFileRef {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Ndbcntr;
  friend class NdbDictInterface;
  
  /**
   * For printing
   */
  friend bool printDROP_FILE_REF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 7 );
  STATIC_CONST( GSN = GSN_DROP_FILE_REF );

  enum ErrorCode {
    NoError = 0,
    Busy = 701,
    NoSuchFile = 766,
    DropUndoFileNotSupported = 769
  };

  Uint32 senderData;
  Uint32 senderRef;
  Uint32 masterNodeId;
  Uint32 errorCode;
  Uint32 errorLine; 
  Uint32 errorKey;

};

struct DropFileConf {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Ndbcntr;
  friend class NdbDictInterface;
  
  /**
   * For printing
   */
  friend bool printDROP_FILE_CONF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 4 );
  STATIC_CONST( GSN = GSN_DROP_FILE_CONF );

  Uint32 senderData;
  Uint32 senderRef;
  Uint32 fileId;
  Uint32 fileVersion;
};

#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/DropFilegroupImpl.hpp	05/10/10 21:27:16
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef DROP_FILEGROUP_IMPL_HPP
#define DROP_FILEGROUP_IMPL_HPP

#include "SignalData.hpp"

struct DropFilegroupImplReq {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;

  /**
   * For printing
   */
  friend bool printDROP_FILEGROUP_IMPL_REQ(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 5 );
  
  enum RequestInfo {
    Prepare = 0x1,
    Commit = 0x2,
    Abort = 0x4
  };
  
  Uint32 senderData;
  Uint32 senderRef;
  
  Uint32 requestInfo;
  Uint32 filegroup_id;
  Uint32 filegroup_version;
};

struct DropFilegroupImplRef {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;
  
  /**
   * For printing
   */
  friend bool printDROP_FILEGROUP_IMPL_REF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 3 );

  enum ErrorCode {
    NoError = 0,
    NoSuchFilegroup = 767,
    InvalidFilegroupVersion = 767,
    FilegroupInUse = 768
  };
  
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 errorCode;
};

struct DropFilegroupImplConf {
  /**
   * Sender(s)
   */
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;
  
  /**
   * For printing
   */
  friend bool printDROP_FILEGROUP_IMPL_CONF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 2 );

  Uint32 senderData;
  Uint32 senderRef;
};

struct DropFileImplReq {
  /**
   * Sender(s) / Reciver(s)
   */
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;

  /**
   * For printing
   */
  friend bool printDROP_FILE_IMPL_REQ(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 6 );
  
  enum RequestInfo {
    Prepare = 0x1,
    Commit = 0x2,
    Abort = 0x4
  };
  
  Uint32 senderData;
  Uint32 senderRef;
  
  Uint32 requestInfo;
  Uint32 file_id;
  Uint32 filegroup_id;
  Uint32 filegroup_version;
};

struct DropFileImplRef {
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;
  
  /**
   * For printing
   */
  friend bool printDROP_FILE_IMPL_REF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 5 );

  enum ErrorCode {
    NoError = 0,
    InvalidFilegroup = 767,
    InvalidFilegroupVersion = 767,
    NoSuchFile = 766,
    FileInUse = 770
  };
  
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 errorCode;
  Uint32 fsErrCode;
  Uint32 osErrCode;
};

struct DropFileImplConf {
  friend class Dbdict;
  friend class Tsman;
  friend class Lgman;
  
  
  /**
   * For printing
   */
  friend bool printDROP_FILE_IMPL_CONF(FILE*, const Uint32*, Uint32, Uint16);
  
  STATIC_CONST( SignalLength = 2 );

  Uint32 senderData;
  Uint32 senderRef;
};

#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/DropObj.hpp	05/10/10 21:27:16
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef DROP_OBJ_HPP
#define DROP_OBJ_HPP

#include "DictObjOp.hpp"
#include "SignalData.hpp"

struct DropObjReq 
{
  /**
   * Sender(s)
   */
  friend class Dbdict;

  /**
   * Receiver(s)
   */
  friend class Dbtc;
  friend class Dblqh;
  friend class Dbacc;
  friend class Dbtup;
  friend class Dbtux;
  friend class Dbdih;
  
  friend bool printDROP_OBJ_REQ(FILE *, const Uint32 *, Uint32, Uint16);
  STATIC_CONST( SignalLength = 9 );

  Uint32 op_key;
  Uint32 objId;
  Uint32 objType;
  Uint32 objVersion;

  Uint32 senderRef;
  Uint32 senderData;

  Uint32 requestInfo;

  Uint32 clientRef;
  Uint32 clientData;
};

class DropObjConf {
  /**
   * Sender(s)
   */
  friend class Dbtc;
  friend class Dblqh;
  friend class Dbacc;
  friend class Dbtup;
  friend class Dbtux;
  friend class Dbdih;

  /**
   * Receiver(s)
   */
  friend class Dbdict;

  friend bool printDROP_OBJ_CONF(FILE *, const Uint32 *, Uint32, Uint16);
public:
  STATIC_CONST( SignalLength = 3 );

private:
  Uint32 senderRef;
  Uint32 senderData;
  Uint32 objId;
};

class DropObjRef {
  /**
   * Sender(s)
   */
  friend class Dbtc;
  friend class Dblqh;
  friend class Dbacc;
  friend class Dbtup;
  friend class Dbtux;
  friend class Dbdih;

  /**
   * Receiver(s)
   */
  friend class Dbdict;

  friend bool printDROP_OBJ_REF(FILE *, const Uint32 *, Uint32, Uint16);
public:
  STATIC_CONST( SignalLength = 4 );

  enum ErrorCode {
    NoSuchObj = 1,
    DropWoPrep = 2, // Calling Drop with first calling PrepDrop
    PrepDropInProgress = 3,
    DropInProgress = 4,
    NF_FakeErrorREF = 5
  };
  
private:
  Uint32 senderRef;
  Uint32 senderData;
  Uint32 objId;
  Uint32 errorCode;
};

#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/Extent.hpp	05/10/10 21:27:16
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef NDB_EXTENT_HPP
#define NDB_EXTENT_HPP

#include "SignalData.hpp"

struct AllocExtentReq {
  /**
   * Sender(s) / Reciver(s)
   */

  /**
   * For printing
   */
  
  STATIC_CONST( SignalLength = 3 );

  enum ErrorCode {
    UnmappedExtentPageIsNotImplemented = 1,
    NoExtentAvailable = 2
  };
  
  union 
  {
    struct 
    {
      Uint32 tablespace_id;
      Uint32 table_id;
      Uint32 fragment_id;
    } request;
    struct 
    {
      Uint32 errorCode;
      Local_key page_id;
      Uint32 page_count;
    } reply;
  };
};

struct FreeExtentReq {
  /**
   * Sender(s) / Reciver(s)
   */

  /**
   * For printing
   */
  
  STATIC_CONST( SignalLength = 4 );

  enum ErrorCode {
    UnmappedExtentPageIsNotImplemented = 1
  };
  
  union 
  {
    struct 
    {
      Local_key key;
      Uint32 table_id;
      Uint32 tablespace_id;
    } request;
    struct 
    {
      Uint32 errorCode;
    } reply;
  };
};

struct AllocPageReq {
  /**
   * Sender(s) / Reciver(s)
   */

  /**
   * For printing
   */
  
  STATIC_CONST( SignalLength = 3 );

  enum ErrorCode {
    UnmappedExtentPageIsNotImplemented = 1,
    NoPageFree= 2
  };
  
  Local_key key; // in out
  Uint32 bits;   // in out
  union 
  {
    struct 
    {
      Uint32 table_id;
      Uint32 fragment_id;
      Uint32 tablespace_id;
    } request;
    struct 
    {
      Uint32 errorCode;
    } reply;
  };
};


#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/LgmanContinueB.hpp	05/10/10 21:27:17
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef LGMAN_CONTINUEB_H
#define LGMAN_CONTINUEB_H

#include "SignalData.hpp"

struct LgmanContinueB {

  enum {
    CUT_LOG_TAIL = 0
    ,FILTER_LOG = 1
    ,FLUSH_LOG = 2
    ,PROCESS_LOG_BUFFER_WAITERS = 3
    ,FIND_LOG_HEAD = 4
    ,EXECUTE_UNDO_RECORD = 5
    ,READ_UNDO_LOG = 6
    ,STOP_UNDO_LOG = 7
    ,PROCESS_LOG_SYNC_WAITERS = 8
    ,FORCE_LOG_SYNC = 9
    ,DROP_FILEGROUP = 10
  };
};

#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/PgmanContinueB.hpp	05/10/10 21:27:17
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef PGMAN_CONTINUEB_H
#define PGMAN_CONTINUEB_H

#include "SignalData.hpp"

class PgmanContinueB {
  /**
   * Sender(s)/Reciver(s)
   */
  friend class Pgman;
private:
  enum {
    PROCESS_ALL = 0,
    PROCESS_REQ_DONE = 1
  };
};

#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/RestoreContinueB.hpp	05/10/10 21:27:17
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef RESTORE_CONTINUEB_H
#define RESTORE_CONTINUEB_H

#include "SignalData.hpp"

class RestoreContinueB {
  /**
   * Sender(s)/Reciver(s)
   */
  friend class Restore;
  friend bool printCONTINUEB_RESTORE(FILE * output, const Uint32 * theData, Uint32 len);
private:
  enum {
    START_FILE_THREAD = 0,
    BUFFER_UNDERFLOW  = 1,
    BUFFER_FULL_SCAN  = 2,
    BUFFER_FULL_FRAG_COMPLETE = 3,
    BUFFER_FULL_META  = 4
  };
};

#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/RestoreImpl.hpp	05/10/10 21:27:17
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef RESTORE_SIGNAL_DATA_HPP
#define RESTORE_SIGNAL_DATA_HPP

#include "SignalData.hpp"

struct RestoreLcpReq 
{
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 lcpNo;
  Uint32 tableId;
  Uint32 fragmentId;
  Uint32 lcpId;
  STATIC_CONST( SignalLength = 6 );
};

struct RestoreLcpRef
{
  Uint32 senderData;
  Uint32 senderRef;
  Uint32 errorCode;
  Uint32 extra[1];
  STATIC_CONST( SignalLength = 3 );

  enum ErrorCode 
  {
    OK = 0,
    NoFileRecord = 1,
    OutOfDataBuffer = 2,
    OutOfReadBufferPages = 3,
    InvalidFileFormat = 4
  };
};

struct RestoreLcpConf 
{
  Uint32 senderData;
  Uint32 senderRef;
  STATIC_CONST( SignalLength = 2 );
};

struct RestoreContinueB {
  
  enum {
    RESTORE_NEXT = 0, 
    READ_FILE = 1
  };
};

#endif

--- New file ---
+++ storage/ndb/include/kernel/signaldata/TsmanContinueB.hpp	05/10/10 21:27:18
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef TSMAN_CONTINUEB_H
#define TSMAN_CONTINUEB_H

#include "SignalData.hpp"

class TsmanContinueB {
  /**
   * Sender(s)/Reciver(s)
   */
  friend class Tsman;
private:
  enum {
    LOAD_EXTENT_PAGES = 0,
    SCAN_TABLESPACE_EXTENT_HEADERS = 1,
    SCAN_DATAFILE_EXTENT_HEADERS = 2,
    END_LCP = 3,
    RELEASE_EXTENT_PAGES = 4
  };
};

#endif

--- New file ---
+++ storage/ndb/src/kernel/blocks/dbdih/printSysfile.cpp	05/10/10 21:27:18
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


#include <ndb_global.h>

#include <NdbMain.h>
#include <NdbOut.hpp>
#include <Sysfile.hpp>

void 
usage(const char * prg){
  ndbout << "Usage " << prg 
	 << " P[0-1].sysfile" << endl;  
}

struct NSString {
  Sysfile::ActiveStatus NodeStatus;
  const char * desc;
};

static const
NSString NodeStatusStrings[] = {
  { Sysfile::NS_Active,                 "Active         " },
  { Sysfile::NS_ActiveMissed_1,         "Active missed 1" },
  { Sysfile::NS_ActiveMissed_2,         "Active missed 2" },
  { Sysfile::NS_ActiveMissed_3,         "Active missed 3" },
  { Sysfile::NS_HotSpare,               "Hot spare      " },
  { Sysfile::NS_NotActive_NotTakenOver, "Not active     " },
  { Sysfile::NS_TakeOver,               "Take over      " },
  { Sysfile::NS_NotActive_TakenOver,    "Taken over     " },
  { Sysfile::NS_NotDefined,             "Not defined    " },
  { Sysfile::NS_Standby,                "Stand by       " }
};

const
char * getNSString(Uint32 ns){
  for(Uint32 i = 0; i<(sizeof(NodeStatusStrings)/sizeof(NSString)); i++)
    if((Uint32)NodeStatusStrings[i].NodeStatus == ns)
      return NodeStatusStrings[i].desc;
  return "<Unknown state>";
}

void
fill(const char * buf, int mod){
  int len = strlen(buf)+1;
  ndbout << buf << " ";
  while((len % mod) != 0){
    ndbout << " ";
    len++;
  }
}

void 
print(const char * filename, const Sysfile * sysfile){
  char buf[255];
  ndbout << "----- Sysfile: " << filename 
	 << " seq: " << hex << sysfile->m_restart_seq
	 << " -----" << endl;
  ndbout << "Initial start ongoing: " 
	 << Sysfile::getInitialStartOngoing(sysfile->systemRestartBits) 
	 << ", ";

  ndbout << "Restart Ongoing: "
	 << Sysfile::getRestartOngoing(sysfile->systemRestartBits) 
	 << ", ";

  ndbout << "LCP Ongoing: "
	 << Sysfile::getLCPOngoing(sysfile->systemRestartBits) 
	 << endl;


  ndbout << "-- Global Checkpoint Identities: --" << endl;
  sprintf(buf, "keepGCI = %u", sysfile->keepGCI);
  fill(buf, 40); 
  ndbout << " -- Tail of REDO log" << endl;
  
  sprintf(buf, "oldestRestorableGCI = %u", sysfile->oldestRestorableGCI);
  fill(buf, 40);
  ndbout << " -- " << endl;

  sprintf(buf, "newestRestorableGCI = %u", sysfile->newestRestorableGCI);
  fill(buf, 40);
  ndbout << " -- " << endl;

  sprintf(buf, "latestLCP = %u", sysfile->latestLCP_ID);
  fill(buf, 40);
  ndbout << " -- " << endl;

  ndbout << "-- Node status: --" << endl;
  for(int i = 1; i < MAX_NDB_NODES; i++){
    if(Sysfile::getNodeStatus(i, sysfile->nodeStatus) !=Sysfile::NS_NotDefined){
      sprintf(buf, 
	      "Node %.2d -- %s GCP: %d, NodeGroup: %d, TakeOverNode: %d, "
	      "LCP Ongoing: %s",
	      i, 
	      getNSString(Sysfile::getNodeStatus(i,sysfile->nodeStatus)),
	      sysfile->lastCompletedGCI[i],
	      Sysfile::getNodeGroup(i, sysfile->nodeGroups),
	      Sysfile::getTakeOverNode(i, sysfile->takeOver),
	      BitmaskImpl::get(NdbNodeBitmask::Size, 
			       sysfile->lcpActive, i) != 0 ? "yes" : "no");
      ndbout << buf << endl;
    }
  }
}

NDB_COMMAND(printSysfile, 
	    "printSysfile", "printSysfile", "Prints a sysfile", 16384){ 
  if(argc < 2){
    usage(argv[0]);
    return 0;
  }

  for(int i = 1; i<argc; i++){
    const char * filename = argv[i];
    
    struct stat sbuf;
    const int res = stat(filename, &sbuf);
    if(res != 0){
      ndbout << "Could not find file: \"" << filename << "\"" << endl;
      continue;
    }
    const Uint32 bytes = sbuf.st_size;
    
    Uint32 * buf = new Uint32[bytes/4+1];
    
    FILE * f = fopen(filename, "rb");
    if(f == 0){
      ndbout << "Failed to open file" << endl;
      delete [] buf;
      continue;
    }
    Uint32 sz = fread(buf, 1, bytes, f);
    fclose(f);
    if(sz != bytes){
      ndbout << "Failure while reading file" << endl;
      delete [] buf;
      continue;
    }
    
    print(filename, (Sysfile *)&buf[0]);
    delete [] buf;
    continue;
  }
  return 0;
}

--- New file ---
+++ storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp	05/10/10 21:27:18
/* Copyright (C) 2004 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#define DBTUP_C
#include "Dbtup.hpp"

Dbtup::Disk_alloc_info::Disk_alloc_info(const Tablerec* tabPtrP, 
					Uint32 extent_size)
{
  m_curr_extent_info_ptr_i= RNIL; 
  if (tabPtrP->m_no_of_disk_attributes == 0)
    return;
  
  Uint32 min_size= 4*tabPtrP->m_offsets[DD].m_fix_header_size;
  Uint32 var_size= tabPtrP->m_offsets[DD].m_max_var_offset;
  
  if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0)
  {
    Uint32 recs_per_page= (4*Tup_fixsize_page::DATA_WORDS)/min_size;
    Uint32 pct_free= 0;
    m_page_free_bits_map[0] = recs_per_page; // 100% free
    m_page_free_bits_map[1] = 1;
    m_page_free_bits_map[2] = 0;
    m_page_free_bits_map[3] = 0;
    
    Uint32 max= recs_per_page * extent_size;
    for(Uint32 i = 0; i<EXTENT_SEARCH_MATRIX_ROWS; i++)
    {
      m_total_extent_free_space_thresholds[i] = 
	(EXTENT_SEARCH_MATRIX_ROWS - i - 1)*max/EXTENT_SEARCH_MATRIX_ROWS;

      ndbout_c("%d %d %d %d", max, i, EXTENT_SEARCH_MATRIX_ROWS - i - 1, 
	       m_total_extent_free_space_thresholds[i]);
    }
  }
  else
  {
    abort();
  }

  
}

Uint32
Dbtup::Disk_alloc_info::find_extent(Uint32 sz) const
{
  /**
   * Find an extent with sufficient space for sz
   * Find the biggest available (with most free space)
   * Return position in matrix
   */
  Uint32 mask= EXTENT_SEARCH_MATRIX_COLS - 1;
  for(Uint32 i= 0; i<EXTENT_SEARCH_MATRIX_SIZE; i++)
  {
    // Check that it can cater for request
    if (m_extent_search_matrix[i] < sz)
    {
      i = (i + mask) & ~mask;
      continue;
    }
    
    if (!m_free_extents[i].isEmpty())
    {
      return i;
    }
  }
  
  return RNIL;
}

Uint32
Dbtup::Disk_alloc_info::calc_extent_pos(const Extent_info* extP) const
{
  Uint32 free= extP->m_free_space;
  Uint32 mask= EXTENT_SEARCH_MATRIX_COLS - 1;
  
  Uint32 col= 0, row=0;
  
  /**
   * Find correct row based on total free space
   *   if zero (or very small free space) put 
   *     absolutly last
   */
  {
    
    printf("free space %d free_page_thresholds ", free);
    for(Uint32 i = 0; i<EXTENT_SEARCH_MATRIX_ROWS; i++)
      printf("%d ", m_total_extent_free_space_thresholds[i]);
    ndbout_c("");
    
    const Uint32 *arr= m_total_extent_free_space_thresholds;
    for(; free < * arr++; row++)
      assert(row < EXTENT_SEARCH_MATRIX_ROWS);
  }

  /**
   * Find correct col based on largest available chunk
   */
  {
    const Uint16 *arr= extP->m_free_page_count;
    for(; col < EXTENT_SEARCH_MATRIX_COLS && * arr++ == 0; col++);
  }

  /**
   * NOTE
   *
   *   If free space on extent is small or zero,
   *     col will be = EXTENT_SEARCH_MATRIX_COLS
   *     row will be = EXTENT_SEARCH_MATRIX_ROWS
   *   in that case pos will be col * row = max pos
   *   (as fixed by + 1 in declaration)
   */
  Uint32 pos= (row * (mask + 1)) + (col & mask);
  
  printf("free space %d free_page_count ", free);
  for(Uint32 i = 0; i<EXTENT_SEARCH_MATRIX_COLS; i++)
    printf("%d ", extP->m_free_page_count[i]);
  ndbout_c(" -> row: %d col: %d -> pos= %d", row, col, pos);

  assert(pos < EXTENT_SEARCH_MATRIX_SIZE);
  return pos;
}

/**
 * - Page free bits -
 * 0 = 00 - free - 100% free
 * 1 = 01 - atleast 70% free, 70= pct_free + 2 * (100 - pct_free) / 3
 * 2 = 10 - atleast 40% free, 40= pct_free + (100 - pct_free) / 3
 * 3 = 11 - full - less than pct_free% free, pct_free=10%
 *
 */

int
Dbtup::disk_page_prealloc(Signal* signal, 
			  Ptr<Fragrecord> fragPtr,
			  Local_key* key, Uint32 sz)
{
  int err;
  Uint32 i, ptrI;
  Ptr<Page_request> req;
  Fragrecord* fragPtrP = fragPtr.p; 
  Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
  Uint32 idx= alloc.calc_page_free_bits(sz);
  Tablespace_client tsman(signal, c_tsman,
			  fragPtrP->fragTableId,
			  fragPtrP->fragmentId,
			  fragPtrP->m_tablespace_id);
  
  /**
   * 1) search current dirty pages
   */
  for(i= 0; i <= idx; i++)
  {
    if (!alloc.m_dirty_pages[i].isEmpty())
    {
      ptrI= alloc.m_dirty_pages[i].firstItem;
      Ptr<GlobalPage> page;
      m_global_page_pool.getPtr(page, ptrI);
      
      disk_page_prealloc_dirty_page(alloc, *(PagePtr*)&page, i, sz);
      key->m_page_no= ((Page*)page.p)->m_page_no;
      key->m_file_no= ((Page*)page.p)->m_file_no;
      return 0; // Page in memory
    }
  }
  
  /**
   * Search outanding page requests
   *   callback does not need to access page request again
   *   as it's not the first request to this page
   */
  for(i= 0; i <= idx; i++)
  {
    if (!alloc.m_page_requests[i].isEmpty())
    {
      ptrI= alloc.m_page_requests[i].firstItem;
      Ptr<Page_request> req;
      c_page_request_pool.getPtr(req, ptrI);

      disk_page_prealloc_transit_page(alloc, req, i, sz);
      * key = req.p->m_key;
      //ndbout_c("found transit page");
      return 0;
    }
  }
  
  /**
   * We need to request a page...
   */
  if (!c_page_request_pool.seize(req))
  {
    err= 1;
    //XXX set error code
    ndbout_c("no free request");
    return -err;
  }

  new (req.p) Page_request();

  req.p->m_ref_count= 1;
  req.p->m_frag_ptr_i= fragPtr.i;
  req.p->m_uncommitted_used_space= sz;
  
  int pageBits; // received
  Ptr<Extent_info> ext;
  const Uint32 bits= alloc.calc_page_free_bits(sz); // required
  bool found= false;

  /**
   * Do we have a current extent
   */
  if ((ext.i= alloc.m_curr_extent_info_ptr_i) != RNIL)
  {
    jam();
    c_extent_pool.getPtr(ext);
    if ((pageBits= tsman.alloc_page_from_extent(&ext.p->m_key, bits)) >= 0) 
    {
      jam();
      found= true;
    }
    else
    {
      jam();
      /**
       * The current extent is not in a free list
       *   and since it couldn't accomadate the request
       *   we put it on the free list
       */
      Uint32 pos= alloc.calc_extent_pos(ext.p);
      LocalDLList<Extent_info> list(c_extent_pool, alloc.m_free_extents[pos]);
      list.add(ext);
    }
  }
  
  if (!found)
  {
    Uint32 pos;
    if ((pos= alloc.find_extent(sz)) != RNIL)
    {
      jam();
      LocalDLList<Extent_info> list(c_extent_pool, alloc.m_free_extents[pos]);
      list.first(ext);
      list.remove(ext);
    }
    else
    {
      jam();
      /**
       * We need to alloc an extent
       */
      if (!c_extent_pool.seize(ext))
      {
	//XXX
	err= 2;
	c_page_request_pool.release(req);
	ndbout_c("no free extent info");
	return -err;
      }

      if ((err= tsman.alloc_extent(&ext.p->m_key)) < 0)
      {
	//XXX
	c_extent_pool.release(ext);
	c_page_request_pool.release(req);
	ndbout_c("no free extent");
	return -err;
      }
      
      int pages= err;
      ndbout << "allocated " << pages << " pages: " << ext.p->m_key << endl;
      bzero(ext.p->m_free_page_count, sizeof(ext.p->m_free_page_count));
      ext.p->m_free_space= alloc.m_page_free_bits_map[0] * pages; 
      ext.p->m_free_page_count[0]= pages; // All pages are "free"-est
      c_extent_hash.add(ext);

      LocalSLList<Extent_info, Extent_list_t> 
	list1(c_extent_pool, alloc.m_extent_list);
      list1.add(ext);
    }
    alloc.m_curr_extent_info_ptr_i= ext.i;
    ext.p->m_free_matrix_pos= RNIL;
    pageBits= tsman.alloc_page_from_extent(&ext.p->m_key, bits);
    ndbassert(pageBits >= 0);
  }
  
  /**
   * We have a page from an extent
   */
  *key= req.p->m_key= ext.p->m_key;

  /**
   * We don't know exact free space of page
   *   but we know what page free bits it has.
   *   compute free space based on them
   */
  Uint32 size= alloc.calc_page_free_space((Uint32)pageBits);
  
  ndbassert(size >= sz);
  Uint32 new_size = size - sz;   // Subtract alloc rec
  req.p->m_estimated_free_space= new_size; // Store on page request

  Uint32 newPageBits= alloc.calc_page_free_bits(new_size);
  if (newPageBits != (Uint32)pageBits)
  {
    ndbassert(ext.p->m_free_page_count[pageBits] > 0);
    ext.p->m_free_page_count[pageBits]--;
    ext.p->m_free_page_count[newPageBits]++;
  }
  ndbassert(ext.p->m_free_space >= sz);
  ext.p->m_free_space -= sz;
  
  // And put page request in correct free list
  idx= alloc.calc_page_free_bits(new_size);
  {
    LocalDLList<Page_request> list(c_page_request_pool, 
				   alloc.m_page_requests[idx]);
    
    list.add(req);
  }
  req.p->m_list_index= idx;
  req.p->m_extent_info_ptr= ext.i;

  Page_cache_client::Request preq;
  preq.m_page = *key;
  preq.m_callback.m_callbackData= req.i;
  preq.m_callback.m_callbackFunction = 
    safe_cast(&Dbtup::disk_page_prealloc_callback);
  
  int flags= Page_cache_client::ALLOC_REQ;
  if (pageBits == 0)
  {
    //XXX empty page -> fast to map
    flags |= Page_cache_client::EMPTY_PAGE | Page_cache_client::NO_HOOK;
    preq.m_callback.m_callbackFunction = 
      safe_cast(&Dbtup::disk_page_prealloc_initial_callback);
  }
  
  int res= m_pgman.get_page(signal, preq, flags);
  switch(res)
  {
  case 0:
    break;
  case -1:
    ndbassert(false);
    break;
  default:
    execute(signal, preq.m_callback, res); // run callback
  }
  
  return res;
}

void
Dbtup::disk_page_prealloc_dirty_page(Disk_alloc_info & alloc,
				     Ptr<Page> pagePtr, 
				     Uint32 old_idx, Uint32 sz)
{
  ndbassert(pagePtr.p->list_index == old_idx);

  Uint32 free= pagePtr.p->free_space;
  Uint32 used= pagePtr.p->uncommitted_used_space + sz;
  Uint32 ext= pagePtr.p->m_extent_info_ptr;
  
  ndbassert(free >= used);
  Ptr<Extent_info> extentPtr;
  c_extent_pool.getPtr(extentPtr, ext);

  Uint32 new_idx= alloc.calc_page_free_bits(free - used);
  ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;

  if (old_idx != new_idx)
  {
    LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]);
    LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]);
    old_list.remove(pagePtr);
    new_list.add(pagePtr);

    ndbassert(extentPtr.p->m_free_page_count[old_idx]);
    extentPtr.p->m_free_page_count[old_idx]--;
    extentPtr.p->m_free_page_count[new_idx]++;
    pagePtr.p->list_index= new_idx;  
  }

  pagePtr.p->uncommitted_used_space = used;
  ndbassert(extentPtr.p->m_free_space >= sz);
  extentPtr.p->m_free_space -= sz;
  Uint32 old_pos= extentPtr.p->m_free_matrix_pos;
  if (old_pos != RNIL) // Current extent
  {
    jam();
    Uint32 new_pos= alloc.calc_extent_pos(extentPtr.p);
    if (old_pos != new_pos)
    {
      jam();
      Extent_list old_list(c_extent_pool, alloc.m_free_extents[old_pos]);
      Extent_list new_list(c_extent_pool, alloc.m_free_extents[new_pos]);
      old_list.remove(extentPtr);
      new_list.add(extentPtr);
      extentPtr.p->m_free_matrix_pos= new_pos;
    }
  }
}


void
Dbtup::disk_page_prealloc_transit_page(Disk_alloc_info& alloc,
				       Ptr<Page_request> req, 
				       Uint32 old_idx, Uint32 sz)
{
  ndbassert(req.p->m_list_index == old_idx);

  Uint32 free= req.p->m_estimated_free_space;
  Uint32 used= req.p->m_uncommitted_used_space + sz;
  Uint32 ext= req.p->m_extent_info_ptr;
  
  Ptr<Extent_info> extentPtr;
  c_extent_pool.getPtr(extentPtr, ext);

  ndbassert(free >= sz);
  Uint32 new_idx= alloc.calc_page_free_bits(free - sz);
  
  if (old_idx != new_idx)
  {
    DLList<Page_request>::Head *lists = alloc.m_page_requests;
    LocalDLList<Page_request> old_list(c_page_request_pool, lists[old_idx]);
    LocalDLList<Page_request> new_list(c_page_request_pool, lists[new_idx]);
    old_list.remove(req);
    new_list.add(req);

    ndbassert(extentPtr.p->m_free_page_count[old_idx]);
    extentPtr.p->m_free_page_count[old_idx]--;
    extentPtr.p->m_free_page_count[new_idx]++;
    req.p->m_list_index= new_idx;  
  }

  req.p->m_uncommitted_used_space = used;
  req.p->m_estimated_free_space = free - sz;
  ndbassert(extentPtr.p->m_free_space >= sz);
  extentPtr.p->m_free_space -= sz;
  Uint32 old_pos= extentPtr.p->m_free_matrix_pos;
  if (old_pos != RNIL) // Current extent
  {
    jam();
    Uint32 new_pos= alloc.calc_extent_pos(extentPtr.p);
    if (old_pos != new_pos)
    {
      jam();
      Extent_list old_list(c_extent_pool, alloc.m_free_extents[old_pos]);
      Extent_list new_list(c_extent_pool, alloc.m_free_extents[new_pos]);
      old_list.remove(extentPtr);
      new_list.add(extentPtr);
      extentPtr.p->m_free_matrix_pos= new_pos;
    }
  }
}


void
Dbtup::disk_page_prealloc_callback(Signal* signal, 
				Uint32 page_request, Uint32 page_id)
{
  //ndbout_c("disk_alloc_page_callback id: %d", page_id);

  Ptr<Page_request> req;
  c_page_request_pool.getPtr(req, page_request);

  Ptr<GlobalPage> gpage;
  m_global_page_pool.getPtr(gpage, page_id);

  Ptr<Fragrecord> fragPtr;
  fragPtr.i= req.p->m_frag_ptr_i;
  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
  
  disk_page_prealloc_callback_common(signal, req, fragPtr, gpage);
}

void
Dbtup::disk_page_prealloc_initial_callback(Signal*signal, 
					   Uint32 page_request, 
					   Uint32 page_id)
{
  //ndbout_c("disk_alloc_page_callback_initial id: %d", page_id);  
  /**
   * 1) lookup page request
   * 2) lookup page
   * 3) lookup table
   * 4) init page (according to page type)
   * 5) call ordinary callback
   */
  Ptr<Page_request> req;
  c_page_request_pool.getPtr(req, page_request);

  Ptr<GlobalPage> gpage;
  m_global_page_pool.getPtr(gpage, page_id);

  Ptr<Fragrecord> fragPtr;
  fragPtr.i= req.p->m_frag_ptr_i;
  ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);

  Ptr<Tablerec> tabPtr;
  tabPtr.i = fragPtr.p->fragTableId;
  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);

  Ptr<Extent_info> extentPtr;
  c_extent_pool.getPtr(extentPtr, req.p->m_extent_info_ptr);

  Page* page= (Page*)gpage.p;
  page->m_page_no= req.p->m_key.m_page_no;
  page->m_file_no= req.p->m_key.m_file_no;
  page->m_table_id= fragPtr.p->fragTableId;
  page->m_fragment_id = fragPtr.p->fragmentId;
  page->m_extent_no = extentPtr.p->m_key.m_page_idx; // logical extent no
  page->m_extent_info_ptr= req.p->m_extent_info_ptr;
  page->m_restart_seq = globalData.m_restart_seq;
  page->list_index = 0x8000;
  page->uncommitted_used_space = 0;
  page->nextList = page->prevList = RNIL;
  
  if (tabPtr.p->m_attributes[DD].m_no_of_varsize == 0)
  {
    convertThPage(tabPtr.p->m_offsets[DD].m_fix_header_size, 
		  (Fix_page*)gpage.p);
  }
  else
  {
    abort();
  }
  disk_page_prealloc_callback_common(signal, req, fragPtr, gpage);
}

void
Dbtup::disk_page_prealloc_callback_common(Signal* signal, 
					  Ptr<Page_request> req, 
					  Ptr<Fragrecord> fragPtr, 
					  Ptr<GlobalPage> pagePtr)
{
  Page* page= (Page*)pagePtr.p;

  /**
   * 1) remove page request from Disk_alloc_info.m_page_requests
   * 2) Add page to Disk_alloc_info.m_dirty_pages
   * 3) register callback in pgman (unmap callback)
   * 4) inform pgman about current users
   */
  ndbassert((page->list_index & 0x8000) == 0x8000);
  ndbassert(page->m_extent_info_ptr == req.p->m_extent_info_ptr);
  ndbassert(page->m_page_no == req.p->m_key.m_page_no);
  ndbassert(page->m_file_no == req.p->m_key.m_file_no);
  Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
  
  Uint32 old_idx = req.p->m_list_index;
  Uint32 free= req.p->m_estimated_free_space;
  Uint32 ext = req.p->m_extent_info_ptr;
  Uint32 used= req.p->m_uncommitted_used_space;
  Uint32 real_free = page->free_space;
  Uint32 real_used = used + page->uncommitted_used_space;
 
  ndbassert(real_free >= free);
  ndbassert(real_free >= real_used);
  ndbassert(alloc.calc_page_free_bits(free) == old_idx);
  Uint32 new_idx= alloc.calc_page_free_bits(real_free - real_used);
  
  /**
   * Add to dirty pages
   */
  ArrayPool<Page> *cheat_pool= (ArrayPool<Page>*)&m_global_page_pool;
  LocalDLList<Page> list(* cheat_pool, alloc.m_dirty_pages[new_idx]);
  list.add(*(Ptr<Page>*)&pagePtr);
  page->uncommitted_used_space = real_used;
  page->list_index = new_idx;

  if (old_idx != new_idx || free != real_free)
  {
    Ptr<Extent_info> extentPtr;
    c_extent_pool.getPtr(extentPtr, ext);

    extentPtr.p->m_free_space += (real_free - free);
    
    if (old_idx != new_idx)
    {
      ndbassert(extentPtr.p->m_free_page_count[old_idx]);
      extentPtr.p->m_free_page_count[old_idx]--;
      extentPtr.p->m_free_page_count[new_idx]++;
    }
    
    Uint32 old_pos= extentPtr.p->m_free_matrix_pos;
    if (old_pos != RNIL) // Current extent
    {
      jam();
      Uint32 new_pos= alloc.calc_extent_pos(extentPtr.p);
      if (old_pos != new_pos)
      {
	jam();
	Extent_list old_list(c_extent_pool, alloc.m_free_extents[old_pos]);
	Extent_list new_list(c_extent_pool, alloc.m_free_extents[new_pos]);
	old_list.remove(extentPtr);
	new_list.add(extentPtr);
	extentPtr.p->m_free_matrix_pos= new_pos;
      }
    }
  }
  
  {
    Page_request_list list(c_page_request_pool, 
			   alloc.m_page_requests[old_idx]);
    list.release(req);
  }
}

int
Dbtup::disk_page_load_hook(Uint32 page_id)
{
  Ptr<GlobalPage> gpage;
  m_global_page_pool.getPtr(gpage, page_id);
  
  PagePtr pagePtr= *(PagePtr*)&gpage;
  Uint32 type = pagePtr.p->m_page_header.m_page_type;
  if (unlikely(type != File_formats::PT_Tup_fixsize_page &&
	       type != File_formats::PT_Tup_varsize_page))
  {
    ndbassert(false);
    return 0;
  }
  
  pagePtr.p->list_index |= 0x8000;
  pagePtr.p->nextList = pagePtr.p->prevList = RNIL;

  Local_key key;
  key.m_page_no = pagePtr.p->m_page_no;
  key.m_file_no = pagePtr.p->m_file_no;

  if (unlikely(pagePtr.p->m_restart_seq != globalData.m_restart_seq))
  {
    pagePtr.p->m_restart_seq = globalData.m_restart_seq;
    pagePtr.p->uncommitted_used_space = 0;
    
    Ptr<Tablerec> tabPtr;
    tabPtr.i= pagePtr.p->m_table_id;
    ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
    
    Ptr<Fragrecord> fragPtr;
    getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p);
    
    Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
    Uint32 idx= alloc.calc_page_free_bits(pagePtr.p->free_space);
    
    pagePtr.p->list_index = idx | 0x8000;    

    Extent_info key;
    key.m_key.m_file_no = pagePtr.p->m_file_no;
    key.m_key.m_page_idx = pagePtr.p->m_extent_no;
    Ptr<Extent_info> extentPtr;
    ndbrequire(c_extent_hash.find(extentPtr, key));
    pagePtr.p->m_extent_info_ptr = extentPtr.i;
    return 1;
  }
  
  return 0;
}

void
Dbtup::disk_page_unmap_callback(Uint32 page_id)
{
  Ptr<GlobalPage> gpage;
  m_global_page_pool.getPtr(gpage, page_id);
  PagePtr pagePtr= *(PagePtr*)&gpage;

  Uint32 type = pagePtr.p->m_page_header.m_page_type;
  if (unlikely(type != File_formats::PT_Tup_fixsize_page &&
	       type != File_formats::PT_Tup_varsize_page))
  {
    return ;
  }
  
  Uint32 i = pagePtr.p->list_index;

  Local_key key;
  key.m_page_no = pagePtr.p->m_page_no;
  key.m_file_no = pagePtr.p->m_file_no;

  if ((i & 0x8000) == 0)
  {
    Ptr<Tablerec> tabPtr;
    tabPtr.i= pagePtr.p->m_table_id;
    ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
    
    Ptr<Fragrecord> fragPtr;
    getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p);
    
    Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;

    ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
    LocalDLList<Page> old(*pool, alloc.m_dirty_pages[i]);
    old.remove(pagePtr);

    if (pagePtr.p->uncommitted_used_space == 0)
    {
      Tablespace_client tsman(0, c_tsman,
			      fragPtr.p->fragTableId,
			      fragPtr.p->fragmentId,
			      fragPtr.p->m_tablespace_id);
      
      tsman.unmap_page(&key);
    }
  }
  pagePtr.p->list_index = i | 0x8000;
}

void
Dbtup::disk_page_alloc(Signal* signal, 
		       Tablerec* tabPtrP, Fragrecord* fragPtrP, 
		       Local_key* key, PagePtr pagePtr, Uint32 gci)
{
  Uint32 logfile_group_id= fragPtrP->m_logfile_group_id;

  Uint64 lsn;
  Uint32 old_free = pagePtr.p->free_space;
  Uint32 old_bits= fragPtrP->m_disk_alloc_info.calc_page_free_bits(old_free);
  if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0)
  {
    ndbassert(pagePtr.p->uncommitted_used_space > 0);
    pagePtr.p->uncommitted_used_space--;
    key->m_page_idx= ((Fix_page*)pagePtr.p)->alloc_record();
    lsn= disk_page_undo_alloc(pagePtr.p, key, 1, gci, logfile_group_id);
  }
  else
  {
    Uint32 sz= key->m_page_idx;
    ndbassert(pagePtr.p->uncommitted_used_space >= sz);
    pagePtr.p->uncommitted_used_space -= sz;
    key->m_page_idx= ((Var_page*)pagePtr.p)->
      alloc_record(sz, (Var_page*)ctemp_page, 0);
    
    lsn= disk_page_undo_alloc(pagePtr.p, key, sz, gci, logfile_group_id);
  }

  Uint32 new_free = pagePtr.p->free_space;
  Uint32 new_bits= fragPtrP->m_disk_alloc_info.calc_page_free_bits(new_free);
  
  if (old_bits != new_bits)
  {
    Tablespace_client tsman(signal, c_tsman,
			    fragPtrP->fragTableId,
			    fragPtrP->fragmentId,
			    fragPtrP->m_tablespace_id);

    tsman.update_page_free_bits(key, new_bits, lsn);
  }
}

void
Dbtup::disk_page_free(Signal *signal, 
		      Tablerec *tabPtrP, Fragrecord * fragPtrP,
		      Local_key* key, PagePtr pagePtr, Uint32 gci)
{
  Uint32 page_idx= key->m_page_idx;
  Uint32 logfile_group_id= fragPtrP->m_logfile_group_id;
  Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
  Uint32 old_free= pagePtr.p->free_space;
  Uint32 old_bits= alloc.calc_page_free_bits(old_free);

  Uint32 sz;
  Uint64 lsn;
  if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0)
  {
    sz = 1;
    const Uint32 *src= ((Fix_page*)pagePtr.p)->get_ptr(page_idx, 0);
    lsn= disk_page_undo_free(pagePtr.p, key,
			     src, tabPtrP->m_offsets[DD].m_fix_header_size,
			     gci, logfile_group_id);
    
    ((Fix_page*)pagePtr.p)->free_record(page_idx);
  }
  else
  {
    const Uint32 *src= ((Var_page*)pagePtr.p)->get_ptr(page_idx);
    sz= ((Var_page*)pagePtr.p)->get_entry_len(page_idx);
    lsn= disk_page_undo_free(pagePtr.p, key,
			     src, sz,
			     gci, logfile_group_id);
    
    ((Var_page*)pagePtr.p)->free_record(page_idx, 0);
  }    
  
  Uint32 new_free = pagePtr.p->free_space;
  Uint32 new_bits = alloc.calc_page_free_bits(new_free);
  
  if (old_bits != new_bits)
  {
    Tablespace_client tsman(signal, c_tsman,
			    fragPtrP->fragTableId,
			    fragPtrP->fragmentId,
			    fragPtrP->m_tablespace_id);

    tsman.update_page_free_bits(key, new_bits, lsn);
  }

  Uint32 ext = pagePtr.p->m_extent_info_ptr;
  Uint32 used = pagePtr.p->uncommitted_used_space;
  ndbassert(old_free >= used);
  ndbassert(new_free >= used);
  ndbassert(new_free >= old_free);
  page_idx = pagePtr.p->list_index;
  Uint32 old_idx = page_idx & 0x7FFF;
  Uint32 new_idx = alloc.calc_page_free_bits(new_free - used);
  ndbassert(alloc.calc_page_free_bits(old_free - used) == old_idx);

  Ptr<Extent_info> extentPtr;
  c_extent_pool.getPtr(extentPtr, ext);

  if (old_idx != new_idx)
  {
    ndbassert(extentPtr.p->m_free_page_count[old_idx]);
    extentPtr.p->m_free_page_count[old_idx]--;
    extentPtr.p->m_free_page_count[new_idx]++;

    if (old_idx == page_idx)
    {
      ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
      LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]);
      LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]);
      old_list.remove(pagePtr);
      new_list.add(pagePtr);
      pagePtr.p->list_index = new_idx;
    }
    else
    {
      pagePtr.p->list_index = new_idx | 0x8000;
    }
  }
  
  extentPtr.p->m_free_space += sz;
  Uint32 old_pos = extentPtr.p->m_free_matrix_pos;
  if (old_pos != RNIL)
  {
    Uint32 pos= alloc.calc_extent_pos(extentPtr.p);
    
    if (pos != old_pos)
    {
      Extent_list old_list(c_extent_pool, alloc.m_free_extents[old_pos]);
      Extent_list new_list(c_extent_pool, alloc.m_free_extents[pos]);
      old_list.remove(extentPtr);
      new_list.add(extentPtr);
      extentPtr.p->m_free_matrix_pos= pos;
    }
  }
}

void
Dbtup::disk_page_abort_prealloc(Signal *signal, Fragrecord* fragPtrP, 
				Local_key* key, Uint32 sz)
{
  Page_cache_client::Request req;
  req.m_callback.m_callbackData= sz;
  req.m_callback.m_callbackFunction = 
    safe_cast(&Dbtup::disk_page_abort_prealloc_callback);
  
  int flags= Page_cache_client::DIRTY_REQ;
  memcpy(&req.m_page, key, sizeof(Local_key));

  int res= m_pgman.get_page(signal, req, flags);
  switch(res)
  {
  case 0:
  case -1:
    break;
  default:
    Ptr<GlobalPage> page;
    m_global_page_pool.getPtr(page, (Uint32)res);
    disk_page_abort_prealloc_callback_1(signal, fragPtrP, *(PagePtr*)&page, 
					sz);
  }
}

void
Dbtup::disk_page_abort_prealloc_callback(Signal* signal, 
					 Uint32 sz, Uint32 page_id)
{
  //ndbout_c("disk_alloc_page_callback id: %d", page_id);
  
  Ptr<GlobalPage> gpage;
  m_global_page_pool.getPtr(gpage, page_id);
  
  PagePtr pagePtr= *(PagePtr*)&gpage;
  
  Ptr<Tablerec> tabPtr;
  tabPtr.i= pagePtr.p->m_table_id;
  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
  
  Ptr<Fragrecord> fragPtr;
  getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p);

  disk_page_abort_prealloc_callback_1(signal, fragPtr.p, pagePtr, sz);
}

void
Dbtup::disk_page_abort_prealloc_callback_1(Signal* signal, 
					   Fragrecord* fragPtrP,
					   PagePtr pagePtr,
					   Uint32 sz)
{
  Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
  Uint32 page_idx = pagePtr.p->list_index;
  Uint32 used = pagePtr.p->uncommitted_used_space;
  Uint32 free = pagePtr.p->free_space;
  Uint32 ext = pagePtr.p->m_extent_info_ptr;

  Uint32 old_idx = page_idx & 0x7FFF;
  ndbassert(free >= used);
  ndbassert(used >= sz);
  ndbassert(alloc.calc_page_free_bits(free - used) == old_idx);
  Uint32 new_idx = alloc.calc_page_free_bits(free - used + sz);

  Ptr<Extent_info> extentPtr;
  c_extent_pool.getPtr(extentPtr, ext);
  if (old_idx != new_idx)
  {
    ndbassert(extentPtr.p->m_free_page_count[old_idx]);
    extentPtr.p->m_free_page_count[old_idx]--;
    extentPtr.p->m_free_page_count[new_idx]++;

    if (old_idx == page_idx)
    {
      ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool;
      LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]);
      LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]);
      old_list.remove(pagePtr);
      new_list.add(pagePtr);
      pagePtr.p->list_index = new_idx;
    }
    else
    {
      pagePtr.p->list_index = new_idx | 0x8000;
    }
  }
  
  pagePtr.p->uncommitted_used_space = used - sz;
  extentPtr.p->m_free_space += sz;

  Uint32 old_pos = extentPtr.p->m_free_matrix_pos;
  if (old_pos != RNIL)
  {
    Uint32 pos= alloc.calc_extent_pos(extentPtr.p);
    
    if (pos != old_pos)
    {
      Extent_list old_list(c_extent_pool, alloc.m_free_extents[old_pos]);
      Extent_list new_list(c_extent_pool, alloc.m_free_extents[pos]);
      old_list.remove(extentPtr);
      new_list.add(extentPtr);
      extentPtr.p->m_free_matrix_pos= pos;
    }
  }
}

Uint64
Dbtup::disk_page_undo_alloc(Page* page, const Local_key* key,
			    Uint32 sz, Uint32 gci, Uint32 logfile_group_id)
{
  Logfile_client lsman(this, c_lgman, logfile_group_id);

  Disk_undo::Alloc alloc;
  alloc.m_type_length= (Disk_undo::UNDO_ALLOC << 16) | (sizeof(alloc) >> 2);
  alloc.m_page_no = key->m_page_no;
  alloc.m_file_no_page_idx= key->m_file_no << 16 | key->m_page_idx;
  
  Logfile_client::Change c[1] = {{ &alloc, sizeof(alloc) >> 2 } };
  
  Uint64 lsn= lsman.add_entry<1>(c);
  m_pgman.update_lsn(* key, lsn);

  return lsn;
}

Uint64
Dbtup::disk_page_undo_update(Page* page, const Local_key* key,
			     const Uint32* src, Uint32 sz,
			     Uint32 gci, Uint32 logfile_group_id)
{
  Logfile_client lsman(this, c_lgman, logfile_group_id);

  Disk_undo::Update update;
  update.m_page_no = key->m_page_no;
  update.m_file_no_page_idx= key->m_file_no << 16 | key->m_page_idx;
  update.m_gci= gci;
  
  update.m_type_length= 
    (Disk_undo::UNDO_UPDATE << 16) | (sz + (sizeof(update) >> 2) - 1);

  Logfile_client::Change c[3] = {
    { &update, 3 },
    { src, sz },
    { &update.m_type_length, 1 }
  };

  ndbassert(4*(3 + sz + 1) == (sizeof(update) + 4*sz - 4));
    
  Uint64 lsn= lsman.add_entry<3>(c);
  m_pgman.update_lsn(* key, lsn);

  return lsn;
}
  
Uint64
Dbtup::disk_page_undo_free(Page* page, const Local_key* key,
			   const Uint32* src, Uint32 sz,
			   Uint32 gci, Uint32 logfile_group_id)
{
  Logfile_client lsman(this, c_lgman, logfile_group_id);

  Disk_undo::Free free;
  free.m_page_no = key->m_page_no;
  free.m_file_no_page_idx= key->m_file_no << 16 | key->m_page_idx;
  free.m_gci= gci;
  
  free.m_type_length= 
    (Disk_undo::UNDO_FREE << 16) | (sz + (sizeof(free) >> 2) - 1);
  
  Logfile_client::Change c[3] = {
    { &free, 3 },
    { src, sz },
    { &free.m_type_length, 1 }
  };
  
  ndbassert(4*(3 + sz + 1) == (sizeof(free) + 4*sz - 4));
  
  Uint64 lsn= lsman.add_entry<3>(c);
  m_pgman.update_lsn(* key, lsn);

  return lsn;
}
  
int
Dbtup::disk_restart_alloc_extent(Uint32 tableId, Uint32 fragId, 
				 const Local_key* key, Uint32 pages)
{
  TablerecPtr tabPtr;
  FragrecordPtr fragPtr;
  tabPtr.i = tableId;
  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
  if (tabPtr.p->tableStatus == DEFINED)
  {
    getFragmentrec(fragPtr, fragId, tabPtr.p);
    if (!fragPtr.isNull())
    {
      Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
      
      Ptr<Extent_info> ext;
      ndbrequire(c_extent_pool.seize(ext));
      
      ext.p->m_key = *key;
      ndbout << "allocated " << pages << " pages: " << ext.p->m_key << endl;
      bzero(ext.p->m_free_page_count, sizeof(ext.p->m_free_page_count));
      ext.p->m_free_space= alloc.m_page_free_bits_map[0] * pages; 
      ext.p->m_free_page_count[0]= pages; // All pages are "free"-est
      
      if (alloc.m_curr_extent_info_ptr_i != RNIL)
      {
	Ptr<Extent_info> old;
	c_extent_pool.getPtr(old, alloc.m_curr_extent_info_ptr_i);
	ndbassert(old.p->m_free_matrix_pos == RNIL);
	Uint32 pos= alloc.calc_extent_pos(old.p);
	Extent_list new_list(c_extent_pool, alloc.m_free_extents[pos]);
	new_list.add(old);
	old.p->m_free_matrix_pos= pos;
      }
      
      alloc.m_curr_extent_info_ptr_i = ext.i;
      ext.p->m_free_matrix_pos = RNIL;
      c_extent_hash.add(ext);

      LocalSLList<Extent_info, Extent_list_t> 
	list1(c_extent_pool, alloc.m_extent_list);
      list1.add(ext);
      return 0;
    }
  }

  return -1;
}

void
Dbtup::disk_restart_page_bits(Uint32 tableId, Uint32 fragId,
			      const Local_key*, Uint32 old_bits, Uint32 bits)
{
  TablerecPtr tabPtr;
  FragrecordPtr fragPtr;
  tabPtr.i = tableId;
  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
  getFragmentrec(fragPtr, fragId, tabPtr.p);
  Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
  
  Ptr<Extent_info> ext;
  c_extent_pool.getPtr(ext, alloc.m_curr_extent_info_ptr_i);
  
  Uint32 size= alloc.calc_page_free_space(bits);  
  Uint32 old_size= alloc.calc_page_free_space(old_bits);

  if (bits != old_bits)
  {
    ndbassert(ext.p->m_free_page_count[old_bits] > 0);
    ndbassert(ext.p->m_free_space >= old_size);

    ext.p->m_free_page_count[bits]++;
    ext.p->m_free_page_count[old_bits]--;
    
    ext.p->m_free_space += size;
    ext.p->m_free_space -= old_size;

    Uint32 old_pos = ext.p->m_free_matrix_pos;
    if (old_pos != RNIL)
    {
      Uint32 pos= alloc.calc_extent_pos(ext.p);

      if (pos != old_pos)
      {
	Extent_list old_list(c_extent_pool, alloc.m_free_extents[old_pos]);
	Extent_list new_list(c_extent_pool, alloc.m_free_extents[pos]);
	old_list.remove(ext);
	new_list.add(ext);
	ext.p->m_free_matrix_pos= pos;
      }
    }
  }
}

#include <signaldata/LgmanContinueB.hpp>

static Dbtup::Apply_undo f_undo;

void
Dbtup::disk_restart_undo(Signal* signal, Uint64 lsn,
			 Uint32 type, const Uint32 * ptr, Uint32 len)
{
  f_undo.m_lsn= lsn;
  f_undo.m_ptr= ptr;
  f_undo.m_len= len;
  f_undo.m_type = type;

  Page_cache_client::Request preq;
  switch(f_undo.m_type){
  case File_formats::Undofile::UNDO_LCP_FIRST:
  case File_formats::Undofile::UNDO_LCP:
  {
    ndbrequire(len == 3);
    Uint32 tableId = ptr[1] >> 16;
    Uint32 fragId = ptr[1] & 0xFFFF;
    disk_restart_undo_lcp(tableId, fragId);
    disk_restart_undo_next(signal);
    return;
  }
  case File_formats::Undofile::UNDO_TUP_ALLOC:
  {
    Disk_undo::Alloc* rec= (Disk_undo::Alloc*)ptr;
    preq.m_page.m_page_no = rec->m_page_no;
    preq.m_page.m_file_no  = rec->m_file_no_page_idx >> 16;
    preq.m_page.m_page_idx = rec->m_file_no_page_idx & 0xFFFF;
    break;
  }
  case File_formats::Undofile::UNDO_TUP_UPDATE:
  {
    Disk_undo::Update* rec= (Disk_undo::Update*)ptr;
    preq.m_page.m_page_no = rec->m_page_no;
    preq.m_page.m_file_no  = rec->m_file_no_page_idx >> 16;
    preq.m_page.m_page_idx = rec->m_file_no_page_idx & 0xFFFF;
    break;
  }
  case File_formats::Undofile::UNDO_TUP_FREE:
  {
    Disk_undo::Free* rec= (Disk_undo::Free*)ptr;
    preq.m_page.m_page_no = rec->m_page_no;
    preq.m_page.m_file_no  = rec->m_file_no_page_idx >> 16;
    preq.m_page.m_page_idx = rec->m_file_no_page_idx & 0xFFFF;
    break;
  }
  case File_formats::Undofile::UNDO_TUP_CREATE:
    /**
     * 
     */
  {
    Disk_undo::Create* rec= (Disk_undo::Create*)ptr;
    Ptr<Tablerec> tabPtr;
    tabPtr.i= rec->m_table;
    ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
    for(Uint32 i = 0; i<MAX_FRAG_PER_NODE; i++)
      if (tabPtr.p->fragrec[i] != RNIL)
	disk_restart_undo_lcp(tabPtr.i, tabPtr.p->fragid[i]);
    disk_restart_undo_next(signal);
    return;
  }
  default:
    ndbrequire(false);
  }

  f_undo.m_key = preq.m_page;
  preq.m_callback.m_callbackFunction = 
    safe_cast(&Dbtup::disk_restart_undo_callback);
  
  int flags = Page_cache_client::NO_HOOK;
  int res= m_pgman.get_page(signal, preq, flags);
  switch(res)
  {
  case 0:
    break; // Wait for callback
  case -1:
    ndbrequire(false);
    break;
  default:
    execute(signal, preq.m_callback, res); // run callback
  }
}

void
Dbtup::disk_restart_undo_next(Signal* signal)
{
  signal->theData[0] = LgmanContinueB::EXECUTE_UNDO_RECORD;
  sendSignal(LGMAN_REF, GSN_CONTINUEB, signal, 1, JBB);
}

void
Dbtup::disk_restart_undo_lcp(Uint32 tableId, Uint32 fragId)
{
  Ptr<Tablerec> tabPtr;
  tabPtr.i= tableId;
  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
  
  if (tabPtr.p->tableStatus == DEFINED)
  {
    FragrecordPtr fragPtr;
    getFragmentrec(fragPtr, fragId, tabPtr.p);
    if (!fragPtr.isNull())
    {
      fragPtr.p->m_undo_complete = true;
    }
  }
}

void
Dbtup::disk_restart_undo_callback(Signal* signal,
				  Uint32 id, 
				  Uint32 page_id)
{
  jamEntry();
  Ptr<GlobalPage> page;
  m_global_page_pool.getPtr(page, page_id);

  Page* pageP = (Page*)page.p;

  bool update = false;
  if (! (pageP->list_index & 0x8000) ||
     pageP->nextList != RNIL ||
     pageP->prevList != RNIL)
  {
    update = true;
    pageP->list_index |= 0x8000;
    pageP->nextList = pageP->prevList = RNIL;
  }

  Ptr<Tablerec> tabPtr;
  tabPtr.i= pageP->m_table_id;
  ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
  
  if (tabPtr.p->tableStatus != DEFINED)
  {
    disk_restart_undo_next(signal);
    return;
  }

  Ptr<Fragrecord> fragPtr;
  getFragmentrec(fragPtr, pageP->m_fragment_id, tabPtr.p);
  if(fragPtr.isNull())
  {
    disk_restart_undo_next(signal);
    return;
  }
    
  Local_key key;
  key.m_page_no = pageP->m_page_no;
  key.m_file_no = pageP->m_file_no;

  if (pageP->m_restart_seq != globalData.m_restart_seq)
  {
    {
      Extent_info key;
      key.m_key.m_file_no = pageP->m_file_no;
      key.m_key.m_page_idx = pageP->m_extent_no;
      Ptr<Extent_info> extentPtr;
      if (c_extent_hash.find(extentPtr, key))
      {
	pageP->m_extent_info_ptr = extentPtr.i;
      }
      else
      {
	/**
	 * Extent was not allocated at start of LCP
	 *  (or was freed during)
	 * I.e page does not need to be undoed as it's
	 *   really free
	 */
	disk_restart_undo_next(signal);
	return;
      }
    }
    
    update= true;
    pageP->m_restart_seq = globalData.m_restart_seq;
    pageP->uncommitted_used_space = 0;
    
    Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info;
    Uint32 idx= alloc.calc_page_free_bits(pageP->free_space);
    
    pageP->list_index = idx | 0x8000;    
    
  }
  
  Uint64 lsn = 0;
  lsn += pageP->m_page_header.m_page_lsn_hi; lsn <<= 32;
  lsn += pageP->m_page_header.m_page_lsn_lo;
  
  if (f_undo.m_lsn <= lsn)
  {
    Uint32 tableId= pageP->m_table_id;
    Uint32 fragId = pageP->m_fragment_id;
    
    f_undo.m_table_ptr.i= tableId;
    if (tableId < cnoOfTablerec)
    {
      ptrCheckGuard(f_undo.m_table_ptr, cnoOfTablerec, tablerec);

      if (f_undo.m_table_ptr.p->tableStatus == DEFINED)
      {
	getFragmentrec(f_undo.m_fragment_ptr, fragId, f_undo.m_table_ptr.p);
	if (!f_undo.m_fragment_ptr.isNull())
	{
	  if (!f_undo.m_fragment_ptr.p->m_undo_complete)
	  {
	    f_undo.m_page_ptr.i = page_id;
	    f_undo.m_page_ptr.p = pageP;
	    
	    update = true;
	    ndbout_c("applying %lld", f_undo.m_lsn);
	    /**
	     * Apply undo record
	     */
	    switch(f_undo.m_type){
	    case File_formats::Undofile::UNDO_TUP_ALLOC:
	      disk_restart_undo_alloc(&f_undo);
	      break;
	    case File_formats::Undofile::UNDO_TUP_UPDATE:
	      disk_restart_undo_update(&f_undo);
	      break;
	    case File_formats::Undofile::UNDO_TUP_FREE:
	      disk_restart_undo_free(&f_undo);
	      break;
	    default:
	      ndbrequire(false);
	    }
	    
	    disk_restart_undo_page_bits(&f_undo);
	    
	    lsn = f_undo.m_lsn - 1; // make sure undo isn't run again...
	  }
	  else
	  {
	    ndbout_c("lsn %lld frag undo complete", f_undo.m_lsn);
	  }
	}
	else
	{
	  ndbout_c("lsn %lld table not defined", f_undo.m_lsn);
	}
      }
      else
      {
	ndbout_c("lsn %lld no such table", f_undo.m_lsn);
      }
    }
    else
    {
      ndbout_c("f_undo.m_lsn %lld > lsn %lld -> skip",
	       f_undo.m_lsn, lsn);
    }
    
    if (update)
    {
      m_pgman.update_lsn(f_undo.m_key, lsn);
    }
  }

  disk_restart_undo_next(signal);
}

void
Dbtup::disk_restart_undo_alloc(Apply_undo* undo)
{
  ndbassert(undo->m_page_ptr.p->m_file_no == undo->m_key.m_file_no);
  ndbassert(undo->m_page_ptr.p->m_page_no == undo->m_key.m_page_no);
  if (undo->m_table_ptr.p->m_attributes[DD].m_no_of_varsize == 0)
  {
    ((Fix_page*)undo->m_page_ptr.p)->free_record(undo->m_key.m_page_idx);
  }
  else
    ((Var_page*)undo->m_page_ptr.p)->free_record(undo->m_key.m_page_idx, 0);
}

void
Dbtup::disk_restart_undo_update(Apply_undo* undo)
{
  Uint32* ptr;
  Uint32 len= undo->m_len - 4;
  if (undo->m_table_ptr.p->m_attributes[DD].m_no_of_varsize == 0)
  {
    ptr= ((Fix_page*)undo->m_page_ptr.p)->get_ptr(undo->m_key.m_page_idx, len);
    ndbrequire(len == undo->m_table_ptr.p->m_offsets[DD].m_fix_header_size);
  }
  else
  {
    ptr= ((Var_page*)undo->m_page_ptr.p)->get_ptr(undo->m_key.m_page_idx);
    abort();
  }  
  
  const Disk_undo::Update *update = (const Disk_undo::Update*)undo->m_ptr;
  const Uint32* src= update->m_data;
  memcpy(ptr, src, 4 * len);
}

void
Dbtup::disk_restart_undo_free(Apply_undo* undo)
{
  Uint32* ptr, idx = undo->m_key.m_page_idx;
  Uint32 len= undo->m_len - 4;
  if (undo->m_table_ptr.p->m_attributes[DD].m_no_of_varsize == 0)
  {
    ndbrequire(len == undo->m_table_ptr.p->m_offsets[DD].m_fix_header_size);
    idx= ((Fix_page*)undo->m_page_ptr.p)->alloc_record(idx);
    ptr= ((Fix_page*)undo->m_page_ptr.p)->get_ptr(idx, len);
  }
  else
  {
    abort();
  }  
  
  ndbrequire(idx == undo->m_key.m_page_idx);
  const Disk_undo::Free *free = (const Disk_undo::Free*)undo->m_ptr;
  const Uint32* src= free->m_data;
  memcpy(ptr, src, 4 * len);
}

void
Dbtup::disk_restart_undo_page_bits(Apply_undo* undo)
{
  Fragrecord* fragPtrP = undo->m_fragment_ptr.p;
  Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info;
  
  /**
   * Set alloc.m_curr_extent_info_ptr_i to
   *   current this extent (and move old extend into free matrix)
   */
  Ptr<Extent_info> extentPtr;
  c_extent_pool.getPtr(extentPtr, undo->m_page_ptr.p->m_extent_info_ptr);
  
  Uint32 currExtI = alloc.m_curr_extent_info_ptr_i;
  if (extentPtr.i != currExtI && currExtI != RNIL)
  {
    Ptr<Extent_info> currExtPtr;
    c_extent_pool.getPtr(currExtPtr, currExtI);
    ndbrequire(currExtPtr.p->m_free_matrix_pos == RNIL);
    
    Uint32 pos= alloc.calc_extent_pos(currExtPtr.p);
    Extent_list new_list(c_extent_pool, alloc.m_free_extents[pos]);
    new_list.add(currExtPtr);
    currExtPtr.p->m_free_matrix_pos= pos;
    //ndbout_c("moving extent from %d to %d", old_pos, new_pos);
  }
  
  if (extentPtr.i != currExtI)
  {
    Uint32 old_pos = extentPtr.p->m_free_matrix_pos;
    Extent_list old_list(c_extent_pool, alloc.m_free_extents[old_pos]);
    old_list.remove(extentPtr);
    alloc.m_curr_extent_info_ptr_i = extentPtr.i;
    extentPtr.p->m_free_matrix_pos = RNIL;
  }
  else
  {
    ndbrequire(extentPtr.p->m_free_matrix_pos == RNIL);
  }

  /**
   * Compute and update free bits for this page
   */
  Uint32 free = undo->m_page_ptr.p->free_space;
  Uint32 bits = alloc.calc_page_free_bits(free);
  
  Tablespace_client tsman(0, c_tsman,
			  fragPtrP->fragTableId,
			  fragPtrP->fragmentId,
			  fragPtrP->m_tablespace_id);

  tsman.restart_undo_page_free_bits(&undo->m_key, bits, undo->m_lsn);
}

--- New file ---
+++ storage/ndb/src/kernel/blocks/dbtup/DbtupVarAlloc.cpp	05/10/10 21:27:18
/* Copyright (C) 2004 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#define DBTUP_C
#include "Dbtup.hpp"

#define ljam() { jamLine(32000 + __LINE__); }
#define ljamEntry() { jamEntryLine(32000 + __LINE__); }


void Dbtup::init_list_sizes(void)
{
  c_min_list_size[0]= 200;
  c_max_list_size[0]= 499;

  c_min_list_size[1]= 500;
  c_max_list_size[1]= 999;

  c_min_list_size[2]= 1000;
  c_max_list_size[2]= 4079;

  c_min_list_size[3]= 4080;
  c_max_list_size[3]= 8159;

  c_min_list_size[4]= 0;
  c_max_list_size[4]= 199;
}

#if 0
void
Dbtup::free_separate_var_part(Fragrecord* const regFragPtr,
                              Tablerec* const regTabPtr,
                              Tuple_header* tuple_header)
{
  Uint32 page_ref, page_index;
  PagePtr page_ptr;
  page_ref= tuple_header->m_data[regTabPtr->var_offset];
  page_index= page_ref & MAX_TUPLES_PER_PAGE;
  page_ptr.i= page_ref >> MAX_TUPLES_BITS;
  ptrCheckGuard(page_ptr, cnoOfPage, cpage);
  free_var_rec(regFragPtr,
               regTabPtr,
               (Var_page*)page_ptr.p,
               page_index);
}


void
Dbtup::abort_separate_var_part(Uint32 var_page_ref,
                               const Uint32* copy_var_part,
                               Uint32 copy_var_size)
{
  Uint32 page_index;
  PagePtr var_page_ptr;
  page_index= var_page_ref & MAX_TUPLES_PER_PAGE;
  var_page_ptr.i= var_page_ref >> MAX_TUPLES_BITS;
  ptrCheckGuard(var_page_ptr, cnoOfPage, cpage);
  Uint32 *ptr= ((Var_page*)var_page_ptr.p)->get_ptr(page_index);
  MEMCOPY_NO_WORDS(ptr, copy_var_part, copy_var_size);
}

void
Dbtup::shrink_entry(Fragrecord* const regFragPtr,
                    Var_page* const page_ptr,
                    Uint32 page_index,
                    Uint32 new_size)
{
  
  page_ptr->shrink_entry(page_index, new_size);
  update_free_page_list(regFragPtr, page_ptr);
}

void
Dbtup::check_entry_size(KeyReqStruct* req_struct,
                        Operationrec* regOperPtr,
			Fragrecord* const regFragPtr,
                        Tablerec* const regTabPtr)
{
#if 0
  Uint32 vp_index, no_var_attr, total_var_size, add_size, new_size, entry_len;
  Uint32 vp_offset, tuple_size, var_part_local;
  Uint32 *var_data_part, *var_link;
  PagePtr var_page_ptr;
  Uint32* tuple_ptr= req_struct->m_tuple_ptr;
  Uint32 page_index= regOperPtr->m_tuple_location.m_page_idx;
  tuple_size= regTabPtr->tupheadsize;
  no_var_attr= regTabPtr->no_var_attr;
  var_part_local= get_var_part_local(* (tuple_ptr+1));
  add_size= regTabPtr->var_array_wsize;
  var_link= tuple_ptr+tuple_size;
  if (var_part_local == 1) {
    ljam();
    var_data_part= var_link;
    var_page_ptr.p= req_struct->fix_page_ptr.p;
    add_size+= tuple_size;
    vp_index= regOperPtr->m_tuple_location.m_page_idx;
  } else {
    ljam();
    entry_len= get_entry_len(req_struct->var_page_ptr, page_index);
    if (entry_len > (tuple_size + 1)) {
      ljam();
      shrink_entry(regFragPtr,
                   req_struct->fix_page_ptr,
                   page_index,
                   tuple_size + 1);
    } else {
      ndbassert(entry_len == (tuple_size + 1));
    }
    set_up_var_page(*var_link,
                    regFragPtr,
                    var_page_ptr,
                    vp_index,
                    vp_offset);
    var_data_part= &var_page_ptr.p->pageWord[vp_offset];
  }
  total_var_size= calculate_total_var_size((uint16*)var_data_part,
                                           no_var_attr);
  new_size= total_var_size + add_size;
  entry_len= get_entry_len(var_page_ptr.p, vp_index);
  if (new_size < entry_len) {
    ljam();
    shrink_entry(regFragPtr,
                 var_page_ptr.p,
                 vp_index,
                 new_size);
  } else {
    ndbassert(entry_len == new_size);
  }
#endif
}

inline
void
Dbtup::grow_entry(Fragrecord* const regFragPtr,
                  Var_page* page_header,
                  Uint32 page_index,
                  Uint32 growth_len)
{
  page_header->grow_entry(page_index, growth_len);
  update_free_page_list(regFragPtr, page_header);
}


void
Dbtup::setup_varsize_part(KeyReqStruct* req_struct,
			  Operationrec* const regOperPtr,
			  Tablerec* const regTabPtr)
{
  Uint32 num_var_attr;
  Uint32 var_data_wsize;
  Uint32* var_data_ptr;
  Uint32* var_data_start;
  
  Uint32 page_index= regOperPtr->m_tuple_location.m_page_idx;
  if (regTabPtr->var_sized_record) {
    ljam();
    num_var_attr= regTabPtr->no_var_attr;
    if (!(req_struct->m_tuple_ptr->m_header_bits & Tuple_header::CHAINED_ROW))
    {
      ljam();
      var_data_ptr= req_struct->m_tuple_ptr->m_data+regTabPtr->var_offset;
      req_struct->var_page_ptr.i = req_struct->fix_page_ptr.i;
      req_struct->var_page_ptr.p = (Var_page*)req_struct->fix_page_ptr.p;
      req_struct->vp_index= page_index;
    } else {
      Uint32 var_link= req_struct->m_tuple_ptr->m_data[regTabPtr->var_offset];
      ljam();
      
      Uint32 vp_index= var_link & MAX_TUPLES_PER_PAGE;
      PagePtr var_page_ptr;
      var_page_ptr.i= var_link >> MAX_TUPLES_BITS;
      ptrCheckGuard(var_page_ptr, cnoOfPage, cpage);
      
      req_struct->vp_index= vp_index;
      req_struct->var_page_ptr.i= var_page_ptr.i;
      req_struct->var_page_ptr.p= (Var_page*)var_page_ptr.p;
      
      var_data_ptr= ((Var_page*)var_page_ptr.p)->get_ptr(vp_index);
      req_struct->fix_var_together= false;
    }
    var_data_start= &var_data_ptr[regTabPtr->var_array_wsize];
    req_struct->var_len_array= (Uint16*)var_data_ptr;
    req_struct->var_data_start= var_data_start;
    var_data_wsize= init_var_pos_array(req_struct->var_len_array,
                                       &req_struct->var_pos_array[0],
                                       num_var_attr);
    req_struct->var_data_end= &var_data_start[var_data_wsize];
  } 
}


bool
Dbtup::compress_var_sized_part_after_update(KeyReqStruct *req_struct,
                                            Operationrec* const regOperPtr,
                                            Fragrecord* const regFragPtr,
                                            Tablerec* const regTabPtr)
{
  Uint32 entry_len, old_var_len, new_size, total_size;
  Uint32* used_var_data_start= req_struct->var_data_start;
  total_size= calculate_total_var_size(req_struct->var_len_array,
                                       regTabPtr->no_var_attr);
  entry_len= req_struct->var_page_ptr.p->get_entry_len(req_struct->vp_index);
  if (req_struct->fix_var_together) {
    ljam();
    old_var_len= entry_len -
                  (regTabPtr->tupheadsize + regTabPtr->var_array_wsize);
  } else {
    ljam();
    old_var_len= entry_len - regTabPtr->var_array_wsize;
  }
  if (total_size > old_var_len) {
    ljam();
    /**
     * The new total size of the variable part is greater than it was before
     * the update. We will need to increase the size of the record or split
     * it into a fixed part and a variable part.
     */
    if (! handle_growth_after_update(req_struct,
                                     regFragPtr,
                                     regTabPtr,
                                     (total_size - old_var_len))) {
      ljam();
      return false;
    }
  } else if (total_size < old_var_len) {
    ljam();
    /**
     * The new total size is smaller than what it was before we started.
     * In one case we can shrink immediately and this is after an initial
     * insert since we allocate in this case a full sized tuple and there
     * is no problem in shrinking this already before committing.
     *
     * For all other cases we need to keep the space to ensure that we
     * can safely abort (which means in this case to grow back to
     * original size). Thus shrink cannot be done before commit occurs
     * in those cases.
     */
    if (regOperPtr->op_struct.op_type == ZINSERT &&
        regOperPtr->prevActiveOp == RNIL &&
        regOperPtr->nextActiveOp == RNIL) {
      ljam();
      new_size= entry_len - (old_var_len - total_size);
      shrink_entry(regFragPtr,
                   req_struct->var_page_ptr.p,
                   req_struct->vp_index,
                   new_size);
    }
  }
  reset_req_struct_data(regTabPtr,
                        req_struct,
                        regOperPtr->m_tuple_location.m_page_idx);
  copy_back_var_attr(req_struct, regTabPtr, used_var_data_start);
  return true;
}

void
Dbtup::reset_req_struct_data(Tablerec* const regTabPtr,
                             KeyReqStruct* req_struct,
                             Uint32 fix_index)
{
  Var_page *var_page_ptr, *fix_page_ptr;
  Uint32 vp_index;

  fix_page_ptr= (Var_page*)req_struct->fix_page_ptr.p;
  var_page_ptr= req_struct->var_page_ptr.p;
  vp_index= req_struct->vp_index;

  req_struct->m_tuple_ptr= (Tuple_header*)fix_page_ptr->get_ptr(fix_index);
  
  Uint32 vp_len= var_page_ptr->get_entry_len(vp_index);
  
  Uint32 *var_ptr;
  if (req_struct->fix_var_together) 
  {
    ljam();
    var_ptr= req_struct->m_tuple_ptr->m_data+regTabPtr->var_offset;
  }
  else
  {
    var_ptr= var_page_ptr->get_ptr(vp_index);
  }

  req_struct->var_len_array= (Uint16*)(var_ptr);
  req_struct->var_data_start= var_ptr+regTabPtr->var_array_wsize;
  req_struct->var_data_end= var_ptr+regTabPtr->var_array_wsize+vp_len;
}

void
Dbtup::copy_back_var_attr(KeyReqStruct *req_struct,
                          Tablerec* const regTabPtr,
                          Uint32 *source_rec)
{
  Uint32 i, dest_index, vpos_index, byte_size, word_size, num_var_attr;
  Uint32 *dest_rec, max_var_size, entry_len;
  Uint32 total_word_size= 0;

#ifdef VM_TRACE
  entry_len= req_struct->var_page_ptr.p->get_entry_len(req_struct->vp_index);
  if (req_struct->fix_var_together) {
    ljam();
    max_var_size= entry_len - (regTabPtr->tupheadsize +
                               regTabPtr->var_array_wsize);
  } else {
    ljam();
    max_var_size= entry_len - regTabPtr->var_array_wsize;
  }
#endif
  dest_rec= req_struct->var_data_start;
  num_var_attr= regTabPtr->no_var_attr;
  ljam();
  for (i= 0; i < num_var_attr; i++) {
    dest_index= total_word_size;
    byte_size= req_struct->var_len_array[i];
    vpos_index= req_struct->var_pos_array[i];
    word_size= convert_byte_to_word_size(byte_size);
    total_word_size+= word_size;
    req_struct->var_pos_array[i]= total_word_size;
    MEMCOPY_NO_WORDS(&dest_rec[vpos_index],
                     &source_rec[dest_index],
                     word_size);
    ndbassert((vpos_index + word_size) <= max_var_size);
  }
  ndbassert(total_word_size <= max_var_size);
  req_struct->var_pos_array[num_var_attr]= total_word_size;
  req_struct->var_data_end= &req_struct->var_data_start[total_word_size];
}


void
Dbtup::copy_out_var_attr(KeyReqStruct *req_struct,
                         Tablerec* const regTabPtr)
{
  Uint32 i, source_index, byte_size, vpos_index, word_size, last_pos_array;
  Uint32 num_var_attr= regTabPtr->no_var_attr;
  Uint16 copy_pos_array[MAX_ATTRIBUTES_IN_TABLE + 1];
  init_var_len_array(&copy_pos_array[0], regTabPtr);
  init_var_pos_array(&copy_pos_array[0],
                     &copy_pos_array[0],
                     regTabPtr->no_var_attr);
  
  Uint32 *source_rec= req_struct->var_data_start;
  Uint32 *dest_rec= &ctemp_var_record[0];
  Uint32 total_word_size= 0;
  ljam();
  for (i= 0; i < num_var_attr; i++) {
    source_index= total_word_size;
    byte_size= req_struct->var_len_array[i];
    vpos_index= copy_pos_array[i];
    word_size= convert_byte_to_word_size(byte_size);
    total_word_size+= word_size;
    req_struct->var_pos_array[i]= copy_pos_array[i];
    MEMCOPY_NO_WORDS(&dest_rec[source_index],
                     &source_rec[vpos_index],
                     word_size);
  }
  last_pos_array= copy_pos_array[num_var_attr];
  req_struct->var_data_start= dest_rec;
  req_struct->var_data_end= &dest_rec[last_pos_array];
  req_struct->var_part_updated= true;
  req_struct->var_pos_array[num_var_attr]= last_pos_array;
}


Uint32
Dbtup::calculate_total_var_size(Uint16* var_len_array,
                                Uint32 num_var_attr)
{
  Uint32 i, byte_size, word_size, total_size;
  total_size= 0;
  for (i= 0; i < num_var_attr; i++) {
    byte_size= var_len_array[i];
    word_size= convert_byte_to_word_size(byte_size);
    total_size+= word_size;
  }
  return total_size;
}

Uint32
Dbtup::init_var_pos_array(Uint16* var_len_array,
                          Uint16* var_pos_array,
                          Uint32 num_var_attr)
{
  Uint32 i, real_len, word_len;
  Uint32 curr_pos= 0;
  for (i= 0, curr_pos= 0; i < num_var_attr; i++) {
    real_len= var_len_array[i];
    var_pos_array[i]= curr_pos;
    word_len= convert_byte_to_word_size(real_len);
    curr_pos+= word_len;
  }
  var_pos_array[num_var_attr]= curr_pos;
  return curr_pos;
}

void
Dbtup::init_var_len_array(Uint16 *var_len_array, Tablerec *tab_ptr)
{
  Uint32 array_ind= 0;
  Uint32 attr_descr, i;
  Uint32 no_of_attr= tab_ptr->noOfAttr;
  Uint32 descr_start= tab_ptr->tabDescriptor;
  TableDescriptor *tab_descr= &tableDescriptor[descr_start];
  ndbrequire(descr_start + (no_of_attr << ZAD_LOG_SIZE) <= cnoOfTabDescrRec);
  for (i= 0; i < no_of_attr; i++) {
    attr_descr= tab_descr[i * ZAD_SIZE].tabDescr;
    if (AttributeDescriptor::getArrayType(attr_descr) == 0) {
      Uint32 bits_used= AttributeDescriptor::getArraySize(attr_descr) *
                        (1 << AttributeDescriptor::getSize(attr_descr));
      Uint32 no_attr_bytes= ((bits_used + 7) >> 3);
      var_len_array[array_ind++]= no_attr_bytes;
    }
  }
}

#endif

/*
  Allocator for variable sized segments
  Part of the external interface for variable sized segments

  This method is used to allocate and free variable sized tuples and
  parts of tuples. This part can be used to implement variable sized
  attributes without wasting memory. It can be used to support small
  BLOB's attached to the record. It can also be used to support adding
  and dropping attributes without the need to copy the entire table.

  SYNOPSIS
    frag_ptr         A pointer to the fragment description
    tab_ptr          A pointer to the table description
    alloc_size       Size of the allocated record
    signal           The signal object to be used if a signal needs to
                     be sent
  RETURN VALUES
    Returns true if allocation was successful otherwise false

    page_offset      Page offset of allocated record
    page_index       Page index of allocated record
    page_ptr         The i and p value of the page where the record was
                     allocated
*/
Uint32* Dbtup::alloc_var_rec(Fragrecord* const frag_ptr,
			     Tablerec* const tab_ptr,
			     Uint32 alloc_size,
			     Local_key* key,
			     Uint32 * out_frag_page_id,
			     Uint32 base)
{
  Var_page* page_header;
  PagePtr page_ptr;
  page_ptr.i= get_alloc_page(frag_ptr, (alloc_size + 1));
  if (page_ptr.i == RNIL) { 
    ljam();
    if ((page_ptr.i= getEmptyPage(frag_ptr)) == RNIL) {
      ljam();
      return 0;
    }
    ptrCheckGuard(page_ptr, cnoOfPage, cpage);
    page_header= (Var_page*)page_ptr.p;
    page_header->init();
    insert_free_page(frag_ptr, page_header, MAX_FREE_LIST - 1);
    /*
     * Tup scan and index build check ZEMPTY_MM to skip un-init()ed
     * page.  Change state here.  For varsize it means "page in use".
     */
    page_ptr.p->page_state = ZTH_MM_FREE;
  } else {
    ptrCheckGuard(page_ptr, cnoOfPage, cpage);
    ljam();
    page_header= (Var_page*)page_ptr.p;
  }
  Uint32 idx= page_header->alloc_record(alloc_size, 
					(Var_page*)ctemp_page, base);
  
  key->m_page_no= page_ptr.i;
  key->m_page_idx= idx;
  *out_frag_page_id= page_header->frag_page_id;
  update_free_page_list(frag_ptr, page_header);
  return page_header->get_ptr(idx);
}

/*
  Deallocator for variable sized segments
  Part of the external interface for variable sized segments

  SYNOPSIS
    frag_ptr         A pointer to the fragment description
    tab_ptr          A pointer to the table description
    signal           The signal object to be used if a signal needs to
                     be sent
    page_ptr         A reference to the page of the variable sized
                     segment
    free_page_index  Page index on page of variable sized segment
                     which is freed
  RETURN VALUES
    Returns true if deallocation was successful otherwise false
*/
void
Dbtup::free_var_part(Fragrecord* frag_ptr, Tablerec* tab_ptr, 
		     Var_part_ref ref, Uint32 chain)
{
  Local_key tmp;
  PagePtr pagePtr;
  tmp.m_page_idx= ref.m_ref & MAX_TUPLES_PER_PAGE;
  pagePtr.i= tmp.m_page_no= ref.m_ref >> MAX_TUPLES_BITS;
  
  ptrCheckGuard(pagePtr, cnoOfPage, cpage);
  free_var_part(frag_ptr, tab_ptr, &tmp, (Var_page*)pagePtr.p, chain);
}

void Dbtup::free_var_part(Fragrecord* const frag_ptr,
			  Tablerec* const tab_ptr,
			  Local_key* key,
			  Var_page* const page_header,
			  Uint32 chain)
{
  
  Uint32 page_idx= key->m_page_idx;
  page_header->free_record(page_idx, chain);
  
  ndbassert(page_header->free_space <= Var_page::DATA_WORDS);
  if (page_header->free_space == Var_page::DATA_WORDS - 1)
  {
    ljam();
    /*
     This code could be used when we release pages.
    remove_free_page(signal,frag_ptr,page_header,page_header->list_index);
    return_empty_page(frag_ptr, page_header);
    */
    update_free_page_list(frag_ptr, page_header);
  } else {
    ljam();
    update_free_page_list(frag_ptr, page_header);
  }
  return;
}


#if 0
/*
  This method is called whenever the variable part has been updated and
  has grown beyond its original size. This means that more space needs to
  be allocated to the record. If possible this space should be in the
  same page but we might have to allocate more space in a new page.
  In the case of a new page we must still keep the old page and the
  page index since this is the entrance to the record. In this case the
  record might have to be split into a fixed part and a variable part.

  This routine uses cinBuffer as temporary copy buffer. This is no longer
  used since it contains the interpreted program to use in the update
  and this has completed when this function is called.

  SYNOPSIS
  req_struct        The structure for temporary content
  signal            The signal object
  regOperPtr        The operation record
  regFragPtr        The fragment record
  regTabPtr         The table record

  RETURN VALUES
  bool              false if failed due to lack of memory
 */
bool
Dbtup::handle_growth_after_update(KeyReqStruct* req_struct,
                                  Fragrecord* const regFragPtr,
                                  Tablerec* const regTabPtr,
                                  Uint32 growth_len)
{
  Uint32 vp_index, alloc_size, entry_len, curr_var_len;
  Uint32 new_vp_index, new_vp_offset, new_page_ref;
  Uint32 *copy_record= &cinBuffer[0];
  Ptr<Var_page> var_page= req_struct->var_page_ptr;
  Var_page* page_header= var_page.p;
  vp_index= req_struct->vp_index;
  entry_len= var_page.p->get_entry_len(vp_index);
  if (page_header->free_space >= growth_len) {
    /**
     * We will be able to handle the growth without changing the page
     * and page index.
     */
    if (page_header->largest_frag_size() >= entry_len + growth_len) {
      ljam();
      /**
       * In this case we need to copy the entry to the free space area of
       * the page, it is not necessary to reorganise the page.
       */
      MEMCOPY_NO_WORDS(page_header->get_free_space_ptr(),
                       page_header->get_ptr(vp_index),
                       entry_len);
      page_header->set_entry_offset(vp_index, page_header->insert_pos);
      page_header->insert_pos+= entry_len;
    } else {
      ljam();
      /**
       * In this case we need to reorganise the page to fit. To ensure we
       * don't complicate matters we make a little trick here where we
       * fool the reorg_page to avoid copying the entry at hand and copy
       * that separately at the end. This means we need to copy it out of
       * the page before reorg_page to save the entry contents.
       */
      MEMCOPY_NO_WORDS(copy_record,
                       page_header->get_ptr(vp_index),
                       entry_len);
      page_header->set_entry_len(vp_index, 0);
      page_header->free_space+= entry_len;
      reorg_page(page_header);
      MEMCOPY_NO_WORDS(page_header->get_free_space_ptr(),
                       copy_record,
                       entry_len);
      page_header->set_entry_offset(vp_index, page_header->insert_pos);
      growth_len+= entry_len;
    }
    grow_entry(regFragPtr,
	       page_header,
	       vp_index,
               growth_len);
    return true;
  } else {
    /**
     * It is necessary to allocate a segment from a new page.
     */
    if (req_struct->fix_var_together) {
      ljam();
      alloc_size= (entry_len + growth_len) - regTabPtr->tupheadsize;
      curr_var_len= alloc_size - regTabPtr->var_array_wsize;
    } else {
      ljam();
      curr_var_len= entry_len - regTabPtr->var_array_wsize;
      alloc_size= entry_len + growth_len;
    }
    Uint32* ptr, frag_page_id;
    Local_key key;
    if ((ptr= alloc_var_rec(regFragPtr,
			    regTabPtr,
			    alloc_size,
			    &key, &frag_page_id)) == 0)
    {
      /**
       * No space existed for this growth. We need to abort the update.
       */
      ljam();
      terrorCode= ZMEM_NOMEM_ERROR;
      return false;
    }

    /*
     * I need to be careful to copy the var_len_array before freeing it.
     * The data part will be copied by copy_back_var_attr immediately
     * after returning from this method.
     * The updated var part is always in ctemp_var_record since I can
     * never arrive here after a first insert. Thus no danger of the
     * var part written being released.
     */
    MEMCOPY_NO_WORDS(ptr,
                     req_struct->var_len_array,
                     regTabPtr->var_array_wsize);
    req_struct->var_len_array= (Uint16*)ptr;
    if (! req_struct->fix_var_together) {
      ljam();
      /*
       * We need to deallocate the old variable part. This new one will
       * remain the variable part even if we abort the transaction.
       * We don't keep multiple references to the variable parts.
       * The copy data for abort is still kept in the copy record.
       */
      free_separate_var_part(regFragPtr, regTabPtr, req_struct->m_tuple_ptr);
    } else {
      ljam();
      req_struct->fix_var_together= false;
    }
    page_header= (Var_page*)var_page.p;
    new_page_ref= (key.m_page_no << MAX_TUPLES_BITS) + key.m_page_idx;
    req_struct->m_tuple_ptr->m_data[regTabPtr->var_offset] = new_page_ref;
    Uint32 bits= req_struct->m_tuple_ptr->m_header_bits;
    req_struct->m_tuple_ptr->m_header_bits |= Tuple_header::CHAINED_ROW;
    req_struct->var_page_ptr= var_page;
    req_struct->vp_index= key.m_page_idx;
  }
  return true;
}
#endif


/* ------------------------------------------------------------------------ */
// Get a page from one of free lists. If the desired free list is empty we
// try with the next until we have tried all possible lists.
/* ------------------------------------------------------------------------ */
Uint32 Dbtup::get_alloc_page(Fragrecord* const frag_ptr, Uint32 alloc_size)
{
  Uint32 i, start_index, loop_count= 0;
  PagePtr page_ptr;

  start_index= calculate_free_list_impl(alloc_size);
  if (start_index == (MAX_FREE_LIST - 1)) {
    ljam();
  } else {
    ljam();
    ndbrequire(start_index < (MAX_FREE_LIST - 1));
    start_index++;
  }
  for (i= start_index; i < MAX_FREE_LIST; i++) {
    ljam();
    if (frag_ptr->free_var_page_array[i] != RNIL) {
      ljam();
      return frag_ptr->free_var_page_array[i];
    }
  }
  ndbrequire(start_index > 0);
  i= start_index - 1;
  page_ptr.i= frag_ptr->free_var_page_array[i];
  while ((page_ptr.i != RNIL) && (loop_count++ < 16)) {
    ljam();
    ptrCheckGuard(page_ptr, cnoOfPage, cpage);
    Var_page* page_header= (Var_page*)page_ptr.p;
    if (page_header->free_space >= alloc_size) {
      ljam();
      return page_ptr.i;
    }
    page_ptr.i= page_header->next_page;
  }
  return RNIL;
}


/* ------------------------------------------------------------------------ */
// Check if the page needs to go to a new free page list.
/* ------------------------------------------------------------------------ */
void Dbtup::update_free_page_list(Fragrecord* const frag_ptr,
                                  Var_page* page_header)
{
  Uint32 free_space, list_index;
  free_space= page_header->free_space;
  list_index= page_header->list_index;
  if ((free_space < c_min_list_size[list_index]) ||
      (free_space > c_max_list_size[list_index])) {
    Uint32 new_list_index= calculate_free_list_impl(free_space);
    if (list_index != MAX_FREE_LIST) {
      ljam();
      /*
       * Only remove it from its list if it is in a list
       */
      remove_free_page(frag_ptr, page_header, list_index);
    }
    if (free_space < c_min_list_size[new_list_index]) {
      /*
      We have not sufficient amount of free space to put it into any
      free list. Thus the page will not be available for new inserts.
      This can only happen for the free list with least guaranteed free space.
      */
      ljam();
      ndbrequire(new_list_index == 0);
      page_header->list_index= MAX_FREE_LIST;
    } else {
      ljam();
      insert_free_page(frag_ptr, page_header, new_list_index);
    }
  }
}


/* ------------------------------------------------------------------------ */
// Given size of free space, calculate the free list to put it into
/* ------------------------------------------------------------------------ */
Uint32 Dbtup::calculate_free_list_impl(Uint32 free_space_size) const
{
  Uint32 i;
  for (i = 0; i < MAX_FREE_LIST; i++) {
    ljam();
    if (free_space_size <= c_max_list_size[i]) {
      ljam();
      return i;
    }
  }
  ndbrequire(false);
  return 0;
}


/* ------------------------------------------------------------------------ */
// Remove a page from its current free list
/* ------------------------------------------------------------------------ */
void Dbtup::remove_free_page(Fragrecord* frag_ptr,
                             Var_page* page_header,
                             Uint32 index)
{
  Var_page* tmp_page_header;
  if (page_header->prev_page == RNIL) {
    ljam();
    ndbassert(index < MAX_FREE_LIST);
    frag_ptr->free_var_page_array[index]= page_header->next_page;
  } else {
    ljam();
    PagePtr prev_page_ptr;
    prev_page_ptr.i= page_header->prev_page;
    ptrCheckGuard(prev_page_ptr, cnoOfPage, cpage);
    tmp_page_header= (Var_page*)prev_page_ptr.p;
    tmp_page_header->next_page= page_header->next_page;
  }
  if (page_header->next_page != RNIL) {
    ljam();
    PagePtr next_page_ptr;
    next_page_ptr.i= page_header->next_page;
    ptrCheckGuard(next_page_ptr, cnoOfPage, cpage);
    tmp_page_header= (Var_page*) next_page_ptr.p;
    tmp_page_header->prev_page= page_header->prev_page;
  }
}


/* ------------------------------------------------------------------------ */
// Insert a page into a free list on the fragment
/* ------------------------------------------------------------------------ */
void Dbtup::insert_free_page(Fragrecord* frag_ptr,
                             Var_page* page_header,
                             Uint32 index)
{
  Var_page* tmp_page_header;
  Uint32 current_head= frag_ptr->free_var_page_array[index]; 
  Uint32 pagePtrI = page_header->physical_page_id;
  page_header->next_page= current_head;
  ndbassert(index < MAX_FREE_LIST);
  frag_ptr->free_var_page_array[index]= pagePtrI;
  page_header->prev_page= RNIL;
  page_header->list_index= index;
  if (current_head != RNIL) {
    ljam();
    PagePtr head_page_ptr;
    head_page_ptr.i= current_head;
    ptrCheckGuard(head_page_ptr, cnoOfPage, cpage);
    tmp_page_header= (Var_page*)head_page_ptr.p;
    tmp_page_header->prev_page= pagePtrI;
  }
}


--- New file ---
+++ storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.cpp	05/10/10 21:27:19
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "Undo_buffer.hpp"
#define DBTUP_C
#include "Dbtup.hpp"

#if ZPAGE_STATE_POS != 0
#error "PROBLEM!"
#endif

struct UndoPage
{
  File_formats::Page_header m_page_header;
  Uint32 m_state; // Used by buddy alg
  Uint32 m_words_used;
  Uint32 m_ref_count;
  Uint32 m_data[GLOBAL_PAGE_SIZE_WORDS-3-(sizeof(File_formats::Page_header)>>2)];
  
  STATIC_CONST( DATA_WORDS = GLOBAL_PAGE_SIZE_WORDS-3-(sizeof(File_formats::Page_header)>>2) );
};

Undo_buffer::Undo_buffer(Dbtup* tup)
{
  m_tup= tup;
  m_first_free= RNIL;
}

Uint32 *
Undo_buffer::alloc_copy_tuple(Local_key* dst, Uint32 words)
{
  UndoPage* page;
  assert(words);
  if(m_first_free == RNIL)
  {
    Uint32 count;
    m_tup->allocConsPages(1, count, m_first_free);
    if(count == 0)
      return 0;
    page= (UndoPage*)(m_tup->cpage+m_first_free);
    page->m_state= ~ZFREE_COMMON;
    page->m_words_used= 0;
    page->m_ref_count= 0;
  }
  
  if(m_first_free < m_tup->cnoOfPage)
  {
    page= (UndoPage*)(m_tup->cpage+m_first_free);

    Uint32 pos= page->m_words_used;
    if(words + pos > UndoPage::DATA_WORDS)
    {
      m_first_free= RNIL;
      return alloc_copy_tuple(dst, words);
    }
    
    dst->m_page_no = m_first_free;
    dst->m_page_idx = pos;
    
    page->m_ref_count++;
    page->m_words_used = pos + words;
    return page->m_data + pos;
  }
  assert(false);
  return 0;
}

void
Undo_buffer::shrink_copy_tuple(Local_key* key, Uint32 words)
{
  assert(key->m_page_no == m_first_free);
  UndoPage* page= (UndoPage*)(m_tup->cpage+key->m_page_no); 
  assert(page->m_words_used >= words);
  page->m_words_used -= words;
}

void
Undo_buffer::free_copy_tuple(Local_key* key)
{
  UndoPage* page= (UndoPage*)(m_tup->cpage+key->m_page_no);
  Uint32 cnt= page->m_ref_count;
  assert(cnt);

  page->m_ref_count= cnt - 1;
  
  if(cnt - 1 == 0)
  {
    page->m_words_used= 0;
    if(m_first_free == key->m_page_no)
    {
      //ndbout_c("resetting page");
    }
    else 
    {
      //ndbout_c("returning page");
      m_tup->returnCommonArea(key->m_page_no, 1);
    }
  }
  key->setNull();
}

Uint32 *
Undo_buffer::get_ptr(Local_key* key)
{
  return ((UndoPage*)(m_tup->cpage+key->m_page_no))->m_data+key->m_page_idx;
}
  

--- New file ---
+++ storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.hpp	05/10/10 21:27:19
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef __UNDO_BUFFER_HPP
#define __UNDO_BUFFER_HPP

#include <ndb_global.h>
#include <kernel_types.h>

struct Undo_buffer 
{
  Undo_buffer(class Dbtup*);
  
  /**
   * Alloc space for a copy tuple of size <em>words</em>
   *   store address to copy in dst
   *   supply pointer to original in curr
   *
   * @return 0 if unable to alloc space
   */
  Uint32 * alloc_copy_tuple(Local_key* dst, Uint32 words);

  /**
   * Shrink size of copy tuple
   *   note: Only shrink latest allocated tuple
   */
  void shrink_copy_tuple(Local_key* dst, Uint32 words);
  
  /**
   * Free space for copy tuple at key
   */
  void free_copy_tuple(Local_key* key);
  
  /**
   * Get pointer to copy tuple
   */
  Uint32 * get_ptr(Local_key* key);
  
private:
  class Dbtup* m_tup;
  Uint32 m_first_free;
};

#endif

--- New file ---
+++ storage/ndb/src/kernel/blocks/dbtup/test_varpage.cpp	05/10/10 21:27:19
#include <ndb_global.h>
#include "tuppage.hpp"
#include <Vector.hpp>

struct Record
{
  Uint32 idx;
  Uint32 size;
  Uint32* data;
};

#define TRACE(x) x

static
void
cmp(const Uint32 *p1, const Uint32 *p2, Uint32 words)
{
  if(memcmp(p1, p2, 4*words) == 0)
    return;
  
  for(Uint32 i = 0; i<words; i++)
    printf(" %.8x", p1[i]);
  printf("\n");

  for(Uint32 i = 0; i<words; i++)
    printf(" %.8x", p2[i]);
  printf("\n");

  abort();
}

static
void
do_test(int loops, int dist[3])
{
  int allocated= 0;
  Record records[8192];

  Tup_varsize_page page, tmp;
  page.init();

  for(int i = 0; i<loops; i++)
  {
    for(int j = 0; j<allocated; j++)
    {
      Record rec= records[j];
      Uint32* ptr= page.get_ptr(rec.idx);
      cmp(ptr, rec.data, rec.size);
    }
    
loop:
    int op;
    int rnd= rand() % 100;
    for(op= 0; op<3; op++)
      if(rnd < dist[op])
	break;
    
    if(allocated == 0)
      op= 0;
    if(page.free_space <= 2 && op == 0) goto loop;
    
    switch(op){
    case 0: // Alloc
    {
      Record rec;
      rec.size= 1 + (rand() % (page.free_space-1));
      rec.data = new Uint32[rec.size];
      for(Uint32 i= 0; i<rec.size; i++)
      {
	rec.data[i] = rand();
      }
      ndbout << "Alloc " << rec.size << flush;
      rec.idx= page.alloc_record(rec.size, &tmp, 0);
      ndbout << " -> " << rec.idx << endl;
      Uint32* ptr= page.get_ptr(rec.idx);
      memcpy(ptr, rec.data, 4*rec.size);
      records[allocated++] = rec;
      break;
    }
    case 1: // Free
    {
      int no= rand() % allocated;
      Record rec= records[no];
      ndbout << "Free no: " << no << " idx: " << rec.idx << endl;
      Uint32* ptr= page.get_ptr(rec.idx);
      cmp(ptr, rec.data, rec.size);
      delete[] rec.data;
      page.free_record(rec.idx, 0);

      for (unsigned k = no; k + 1 < allocated; k++)
	records[k] = records[k+1];
      allocated--;
      
      break;
    }
    case 2: // Reorg
      ndbout << "Reorg" << endl;      
      page.reorg(&tmp);
      break;
    case 3: 
      ndbout << "Expand" << endl;
      
    }

  }
  ndbout << page << endl;
}

int
main(void)
{
  ndb_init();
  
  int t1[] = { 30, 90, 100 };
  int t2[] = { 45, 90, 100 };
  int t3[] = { 60, 90, 100 };
  int t4[] = { 75, 90, 100 };
  
  do_test(10000, t1);
  do_test(10000, t2);
  do_test(10000, t3);
  do_test(10000, t4);
}

template class Vector<Record>;

--- New file ---
+++ storage/ndb/src/kernel/blocks/dbtup/tuppage.cpp	05/10/10 21:27:19
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <ndb_global.h>
#include "tuppage.hpp"
#include "Dbtup.hpp"

Uint32
Tup_fixsize_page::alloc_record()
{
  assert(free_space);
  Uint32 page_idx = next_free_index;
  assert(page_idx + 1 < DATA_WORDS);

  Uint32 prev = m_data[page_idx] >> 16;
  Uint32 next = m_data[page_idx] & 0xFFFF;

  assert(prev == 0xFFFF);
  assert(m_data[page_idx + 1] == Dbtup::Tuple_header::FREE);
  
  m_data[page_idx + 1] = 0;
  if (next != 0xFFFF)
  {
    assert(free_space > 1);
    Uint32 nextP = m_data[next];
    assert((nextP >> 16) == page_idx);
    m_data[next] = 0xFFFF0000 | (nextP & 0xFFFF);
  }
  else
  {
    assert(free_space == 1);
  }
  
  next_free_index = next;
  free_space--;
  return page_idx;
}

Uint32
Tup_fixsize_page::alloc_record(Uint32 page_idx)
{
  assert(page_idx + 1 < DATA_WORDS);
  if (likely(free_space && m_data[page_idx + 1] == Dbtup::Tuple_header::FREE))
  {
    Uint32 prev = m_data[page_idx] >> 16;
    Uint32 next = m_data[page_idx] & 0xFFFF;
    
    assert(prev != 0xFFFF || (next_free_index == page_idx));
    if (prev == 0xFFFF)
    {
      next_free_index = next;
    }
    else
    {
      Uint32 prevP = m_data[prev];
      m_data[prev] = (prevP & 0xFFFF0000) | next;
    }

    if (next != 0xFFFF)
    {
      Uint32 nextP = m_data[next];
      m_data[next] = (prev << 16) | (nextP & 0xFFFF);
    }
    free_space --;
    m_data[page_idx + 1] = 0;
    return page_idx;
  }
  return ~0;
}

Uint32
Tup_fixsize_page::free_record(Uint32 page_idx)
{
  Uint32 next = next_free_index;
  
  assert(page_idx + 1 < DATA_WORDS);
  assert(m_data[page_idx + 1] != Dbtup::Tuple_header::FREE);

  if (next == 0xFFFF)
  {
    assert(free_space == 0);
  }
  else
  {
    assert(free_space);
    assert(next + 1 < DATA_WORDS);
    Uint32 nextP = m_data[next];
    assert((nextP >> 16) == 0xFFFF);
    m_data[next] = (page_idx << 16) | (nextP & 0xFFFF);
    assert(m_data[next + 1] == Dbtup::Tuple_header::FREE);
  }

  next_free_index = page_idx;
  m_data[page_idx] = 0xFFFF0000 | next;
  m_data[page_idx + 1] = Dbtup::Tuple_header::FREE;
  
  return ++free_space;
}

void
Tup_varsize_page::init()
{
  free_space= DATA_WORDS - 1;
  high_index= 1;
  insert_pos= 0;
  next_free_index= 0xFFFF;
  m_page_header.m_page_type = File_formats::PT_Tup_varsize_page;
}

Uint32
Tup_varsize_page::alloc_record(Uint32 alloc_size, 
			       Tup_varsize_page* temp, Uint32 chain)
{
  assert(free_space >= alloc_size);
  Uint32 largest_size= DATA_WORDS - (insert_pos + high_index);
  if (alloc_size >= largest_size) {
    /*
      We can't fit this segment between the insert position and the end of
      the index entries. We will pack the page so that all free space
      exists between the insert position and the end of the index entries.
    */
    reorg(temp);
    largest_size= DATA_WORDS - (insert_pos + high_index);
  }
  assert(largest_size > alloc_size);

  Uint32 page_idx;
  if (next_free_index == 0xFFFF) {
    /*
      We are out of free index slots. We will extend the array of free
      slots
    */
    page_idx= high_index++;
    free_space--;
  } else {
    // Pick an empty slot among the index entries
    page_idx= next_free_index;
    assert((get_index_word(page_idx) & 0xFFFF0000) == 0);
    next_free_index= get_index_word(page_idx);
  }

  assert(chain == 0 || chain == CHAIN);
  * get_index_ptr(page_idx) = insert_pos + ((chain + alloc_size) << 16);
  
  insert_pos += alloc_size;
  free_space -= alloc_size;
  //ndbout_c("%p->alloc_record(%d%s) -> %d", this,alloc_size, (chain ? " CHAIN" : ""),page_idx);
  return page_idx;
}
  
Uint32
Tup_varsize_page::free_record(Uint32 page_idx, Uint32 chain)
{
  //ndbout_c("%p->free_record(%d%s)", this, page_idx, (chain ? " CHAIN": ""));
  Uint32 *index_ptr= get_index_ptr(page_idx);
  Uint32 index_word= * index_ptr;
  Uint32 entry_pos= index_word & 0xFFFF;
  Uint32 entry_len= (index_word >> 16) & ~CHAIN;
  assert(chain == 0 || chain == CHAIN);
  assert(!(((index_word >> 16) ^ chain) & 0x8000));
#ifdef VM_TRACE
  memset(m_data + entry_pos, 0xF2, 4*entry_len);
#endif
  if (page_idx + 1 == high_index) {
    /*
      We are removing the last in the entry list. We could potentially
      have several free entries also before this. To take that into account
      we will rebuild the free list and thus compress it and update the
      free space accordingly.
    */
    rebuild_index(index_ptr);
  } else {
    * index_ptr= next_free_index;
    next_free_index= page_idx;
  }
  
  free_space+= entry_len;
  // If we're the "last" entry, decrease insert_pos
  insert_pos -= (entry_pos + entry_len == insert_pos ? entry_len : 0);
  
  return free_space;
}

void
Tup_varsize_page::rebuild_index(Uint32* index_ptr)
{
  Uint32 empty= 1;
  Uint32 *end= m_data + DATA_WORDS;

  /**
   * Scan until you find first non empty index pos
   */
  for(index_ptr++; index_ptr < end; index_ptr++)
    if((* index_ptr >> 16) == 0)
      empty++;
    else
      break;
  
  if(index_ptr == end)
  {
    // Totally free page
    high_index = 1;
    free_space += empty;
    next_free_index= 0xFFFF;
    return;
  }

  Uint32 next= 0xFFFF;
  high_index -= empty;
  for(index_ptr++; index_ptr < end; index_ptr++)
  {
    if((* index_ptr >> 16) == 0)
    {
      * index_ptr= next;
      next= (end - index_ptr);
    }
  }
  
  free_space += empty;
  next_free_index= next;
}

void
Tup_varsize_page::reorg(Tup_varsize_page* copy_page)
{
  Uint32 new_insert_pos= 0;
  Uint32 old_insert_pos= insert_pos;

  // Copy key data part of page to a temporary page.
  memcpy(copy_page->m_data, m_data, 4*old_insert_pos);
  assert(high_index > 0);
  Uint32* index_ptr= get_index_ptr(high_index-1);
  Uint32 *end_of_page= m_data + DATA_WORDS;
  for (; index_ptr < end_of_page; index_ptr++)
  {
    Uint32 index_word= * index_ptr;
    Uint32 entry_len= (index_word >> 16) & ~CHAIN;
    if (entry_len != 0) {
      /*
	We found an index item that needs to be packed. 
	We will update the index entry and copy the data to the page.
      */
      Uint32 entry_pos= index_word & 0xffff;
      assert(entry_pos + entry_len <= old_insert_pos);
      assert(new_insert_pos + entry_len <= old_insert_pos);
      * index_ptr= new_insert_pos + (index_word & 0xFFFF0000);
      memcpy(m_data+new_insert_pos, copy_page->m_data+entry_pos, 4*entry_len);
      
      new_insert_pos += entry_len;
    }
  }
  insert_pos= new_insert_pos;
}

NdbOut&
operator<< (NdbOut& out, const Tup_varsize_page& page)
{
  out << "[ Varpage " << &page << ": free: " << page.free_space
      << " (" << (page.DATA_WORDS - (page.insert_pos + page.high_index + 1)) << ")"
      << " insert_pos: " << page.insert_pos 
      << " high_index: " << page.high_index
      << " index: " << flush;
  
  const Uint32 *index_ptr= page.m_data+page.DATA_WORDS-1;
  for(Uint32 i = 1; i<page.high_index; i++, index_ptr--)
  {
    out << " [ " << i;
    if(*index_ptr >> 16)
      out << " pos: " << ((*index_ptr) & 0xFFFF)
	  << " len: " << ((*index_ptr >> 16) & ~page.CHAIN)
	  << (((* index_ptr >> 16) & page.CHAIN) ? " CHAIN " : " ") 
	  << "]" << flush;
    else
      out << " FREE ]" << flush;
  }
  
  out << " free list: " << flush;
  Uint32 next= page.next_free_index;
  while(next != 0xFFFF)
  {
    out << next << " " << flush;
    next= * (page.m_data+page.DATA_WORDS-next);
  }
  out << "]";
  return out;
}

NdbOut&
operator<< (NdbOut& out, const Tup_fixsize_page& page)
{
  out << "[ Fixpage " << &page 
      << ": frag_page: " << page.frag_page_id 
      << " page_no: " << page.m_page_no 
      << " file_no: " << page.m_file_no
      << " table: " << page.m_table_id
      << " fragment: " << page.m_fragment_id 
      << " uncommitted_used_space: " << page.uncommitted_used_space 
      << " free: " << page.free_space;
  
  out << " free list: " << hex << page.next_free_index << " " << flush;
  Uint32 startTuple = page.next_free_index >> 16;
  
#if 0
  Uint32 cnt = 0;
  Uint32 next= startTuple;
  while((next & 0xFFFF) != 0xFFFF)
  {
    cnt++;
    out << dec << "(" << (next & 0xFFFF) << " " << hex << next << ") " << flush;
    assert(page.m_data[(next & 0xFFFF) + 1] == Dbtup::Tuple_header::FREE);
    next= * (page.m_data + ( next & 0xFFFF ));
  }
  assert(cnt == page.free_space);
#endif
  out << "]";
  return out;
}

--- New file ---
+++ storage/ndb/src/kernel/blocks/dbtup/tuppage.hpp	05/10/10 21:27:20
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef __NDB_TUP_PAGE_HPP
#define __NDB_TUP_PAGE_HPP

#include <ndb_types.h>
#include "../diskpage.hpp"

struct Tup_page 
{
  struct File_formats::Page_header m_page_header;
  Uint32 m_restart_seq;
  Uint32 page_state;
  union {
    Uint32 next_page;
    Uint32 nextList;
  };
  union {
    Uint32 prev_page;
    Uint32 prevList;
  };
  Uint32 first_cluster_page;
  Uint32 last_cluster_page;
  Uint32 next_cluster_page;
  Uint32 prev_cluster_page;
  Uint32 frag_page_id;
  Uint32 physical_page_id;
  Uint32 free_space;
  Uint32 next_free_index;
  Uint32 list_index; // free space in page bits/list, 0x8000 means not in free
  Uint32 uncommitted_used_space;
  Uint32 m_page_no;
  Uint32 m_file_no;
  Uint32 m_table_id;
  Uint32 m_fragment_id;
  Uint32 m_extent_no;
  Uint32 m_extent_info_ptr;
  Uint32 unused_ph[9];

  STATIC_CONST( DATA_WORDS = File_formats::NDB_PAGE_SIZE_WORDS - 32 );
  
  Uint32 m_data[DATA_WORDS];
};

struct Tup_fixsize_page
{
  struct File_formats::Page_header m_page_header;
  Uint32 m_restart_seq;
  Uint32 page_state;
  Uint32 next_page;
  Uint32 prev_page;
  Uint32 first_cluster_page;
  Uint32 last_cluster_page;
  Uint32 next_cluster_page;
  Uint32 prev_cluster_page;
  Uint32 frag_page_id;
  Uint32 physical_page_id;
  Uint32 free_space;
  Uint32 next_free_index;
  Uint32 list_index;
  Uint32 uncommitted_used_space;
  Uint32 m_page_no;
  Uint32 m_file_no;
  Uint32 m_table_id;
  Uint32 m_fragment_id;
  Uint32 m_extent_no;
  Uint32 m_extent_info_ptr;
  Uint32 unused_ph[9];

  STATIC_CONST( DATA_WORDS = File_formats::NDB_PAGE_SIZE_WORDS - 32 );
  
  Uint32 m_data[DATA_WORDS];
  
  Uint32* get_ptr(Uint32 page_idx, Uint32 rec_size){
    assert(page_idx + rec_size <= DATA_WORDS);
    return m_data + page_idx;
  }
  
  /**
   * Alloc record from page
   *   return page_idx
   **/
  Uint32 alloc_record();
  Uint32 alloc_record(Uint32 page_idx);
  Uint32 free_record(Uint32 page_idx);
};

struct Tup_varsize_page
{
  struct File_formats::Page_header m_page_header;
  Uint32 m_restart_seq;
  Uint32 page_state;
  Uint32 next_page;
  Uint32 prev_page;
  Uint32 first_cluster_page;
  Uint32 last_cluster_page;
  Uint32 next_cluster_page;
  Uint32 prev_cluster_page;
  Uint32 frag_page_id;
  Uint32 physical_page_id;
  Uint32 free_space;
  Uint32 next_free_index;
  Uint32 list_index;
  Uint32 uncommitted_used_space;
  Uint32 m_page_no;
  Uint32 m_file_no;
  Uint32 m_table_id;
  Uint32 m_fragment_id;
  Uint32 m_extent_no;
  Uint32 m_extent_info_ptr;
  Uint32 high_index; // size of index + 1
  Uint32 insert_pos;
  Uint32 unused_ph[7];
  
  STATIC_CONST( DATA_WORDS = File_formats::NDB_PAGE_SIZE_WORDS - 32 );
  STATIC_CONST( CHAIN = 0x8000 );
  
  Uint32 m_data[DATA_WORDS];
  
  void init();
  
  Uint32* get_free_space_ptr() { 
    return m_data+insert_pos; 
  }
  
  Uint32 largest_frag_size() const { 
    return DATA_WORDS - (high_index + insert_pos); 
  }
  
  Uint32 *get_index_ptr(Uint32 page_idx) {
    assert(page_idx < high_index);
    return (m_data + (DATA_WORDS - page_idx));
  }
  
  Uint32 get_index_word(Uint32 page_idx) const {
    assert(page_idx < high_index);
    return * (m_data + (DATA_WORDS - page_idx));
  }

  /**
   * Alloc record from page, return page_idx
   *   temp is used when having to reorg page before allocating
   */
  Uint32 alloc_record(Uint32 size, Tup_varsize_page* temp, Uint32 chain);
  
  /**
   * Free record from page
   */
  Uint32 free_record(Uint32 page_idx, Uint32 chain);

  void reorg(Tup_varsize_page* temp);
  void rebuild_index(Uint32* ptr);
  
  /**
   * Check if one can grow tuple wo/ reorg
   */
  bool is_space_behind_entry(Uint32 page_index, Uint32 growth_len) const {
    Uint32 idx= get_index_word(page_index); 
    Uint32 pos= idx & 0xFFFF;
    Uint32 len= (idx >> 16) & ~CHAIN;
    if ((pos + len == insert_pos) && 
	(insert_pos + growth_len < DATA_WORDS - high_index))
      return true;
    return false;
  }
  
  void grow_entry(Uint32 page_index, Uint32 growth_len) {
    assert(free_space >= growth_len);
    
    Uint32 *pos= get_index_ptr(page_index);
    Uint32 idx= *pos;
    Uint32 size= (idx >> 16) + growth_len;
    *pos= (idx & 0xFFFF) + (size << 16);
    assert((idx & 0xFFFF) + ((idx >> 16) & ~CHAIN) == insert_pos);
    insert_pos+= growth_len;
    free_space-= growth_len;
  }
  
  void shrink_entry(Uint32 page_index, Uint32 new_size){
    Uint32 *pos= get_index_ptr(page_index);
    Uint32 idx= *pos;
    *pos= (idx & (CHAIN << 16 | 0xFFFF)) + (new_size << 16);
    Uint32 old_size= (idx >> 16) & ~CHAIN;
    
    assert(old_size >= new_size);
    Uint32 shrink = old_size - new_size;
#ifdef VM_TRACE
    memset(m_data + (idx & 0xFFFF) + new_size, 0xF1, 4 * shrink);
#endif
    free_space+= shrink;
    if(insert_pos == ((idx & 0xFFFF) + old_size))
      insert_pos -= shrink;
  }
  
  Uint32* get_ptr(Uint32 page_idx) {
    return m_data + (get_index_word(page_idx) & 0xFFFF);
  }
  
  void set_entry_offset(Uint32 page_idx, Uint32 offset){
    Uint32 *pos= get_index_ptr(page_idx);
    *pos = (* pos & 0xFFFF0000) + offset;
  }
  
  Uint32 get_entry_len(Uint32 page_idx) const {
    return get_index_word(page_idx) >> 16;
  }
  
  void set_entry_len(Uint32 page_idx, Uint32 len) {
    Uint32 *pos= get_index_ptr(page_idx);
    *pos = (len << 16) + (*pos & (CHAIN << 16 | 0xFFFF));
  }
};

NdbOut& operator<< (NdbOut& out, const Tup_varsize_page& page);
NdbOut& operator<< (NdbOut& out, const Tup_fixsize_page& page);

#endif

--- New file ---
+++ storage/ndb/src/kernel/blocks/diskpage.cpp	05/10/10 21:27:20

#include <signaldata/SignalData.hpp>
#include "diskpage.hpp"
#include <NdbOut.hpp>
#include <version.h>
#include <time.h>

void
File_formats::Zero_page_header::init(File_type ft, 
				     Uint32 node_id, 
				     Uint32 version, 
				     Uint32 now)
{
  memcpy(m_magic, "NDBDISK", 8);
  m_byte_order = 0x12345678;
  m_page_size = File_formats::NDB_PAGE_SIZE;
  m_ndb_version = version;
  m_node_id = node_id;
  m_file_type = ft;
  m_time = now;
}

int
File_formats::Zero_page_header::validate(File_type ft, 
					 Uint32 node_id, 
					 Uint32 version, 
					 Uint32 now)
{
  return 0; // TODO Check header
}

NdbOut&
operator<<(NdbOut& out, const File_formats::Zero_page_header& obj)
{
  char buf[256];
  out << "page size:   " << obj.m_page_size << endl;
  out << "ndb version: " << obj.m_ndb_version << ", " <<
    getVersionString(obj.m_ndb_version, 0, buf, sizeof(buf)) << endl;
  out << "ndb node id: " << obj.m_node_id << endl;
  out << "file type:   " << obj.m_file_type << endl;
  out << "time:        " << obj.m_time << ", " 
      << ctime((time_t*)&obj.m_time)<< endl;
  return out;
}

NdbOut&
operator<<(NdbOut& out, const File_formats::Datafile::Zero_page& obj)
{
  out << obj.m_page_header << endl;
  out << "m_file_no: " << obj.m_file_no << endl;
  out << "m_tablespace_id: " << obj.m_tablespace_id << endl;
  out << "m_tablespace_version: " << obj.m_tablespace_version << endl;
  out << "m_data_pages: " << obj.m_data_pages << endl;
  out << "m_extent_pages: " << obj.m_extent_pages << endl;
  out << "m_extent_size: " << obj.m_extent_size << endl;
  out << "m_extent_count: " << obj.m_extent_count << endl;
  out << "m_extent_headers_per_page: " << obj.m_extent_headers_per_page << endl;
  out << "m_extent_header_words: " << obj.m_extent_header_words << endl;
  out << "m_extent_header_bits_per_page: " << obj.m_extent_header_bits_per_page << endl;

  return out;
}

NdbOut&
operator<<(NdbOut& out, const File_formats::Undofile::Zero_page& obj)
{
  out << obj.m_page_header << endl;
  out << "m_file_id: " << obj.m_file_id << endl;
  out << "m_logfile_group_id: " << obj.m_logfile_group_id << endl;
  out << "m_logfile_group_version: " << obj.m_logfile_group_version << endl;
  out << "m_undo_pages: " << obj.m_undo_pages << endl;
  
  return out;
}


--- New file ---
+++ storage/ndb/src/kernel/blocks/diskpage.hpp	05/10/10 21:27:20
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef __NDB_DISKPAGE_HPP
#define __NDB_DISKPAGE_HPP

#include <ndb_types.h>

struct File_formats 
{
  STATIC_CONST( NDB_PAGE_SIZE = 32768 );
  STATIC_CONST( NDB_PAGE_SIZE_WORDS = NDB_PAGE_SIZE >> 2);
  
  enum File_type
  {
    FT_Datafile = 0x1,
    FT_Undofile = 0x2
  };

  struct Page_header 
  {
    Uint32 m_page_lsn_hi;
    Uint32 m_page_lsn_lo;
    Uint32 m_page_type;
  };

  enum Page_type 
  {
    PT_Unallocated        = 0x0,
    PT_Extent_page        = 0x1,
    PT_Tup_fixsize_page   = 0x2,
    PT_Tup_varsize_page   = 0x3,
    PT_Undopage           = 0x4
  };

  struct Zero_page_header
  {
    char   m_magic[8];
    Uint32 m_byte_order;
    Uint32 m_page_size;
    Uint32 m_ndb_version;
    Uint32 m_node_id;
    Uint32 m_file_type;
    Uint32 m_time; // time(0)
    void init(File_type ft, Uint32 node_id, Uint32 version, Uint32 now);
    int validate(File_type ft, Uint32 node_id, Uint32 version, Uint32 now);
  };
  
  STATIC_CONST( NDB_PAGE_HEADER_WORDS = sizeof(Page_header) >> 2);
  
  struct Datafile 
  {
    struct Zero_page 
    {
      struct Zero_page_header m_page_header;
      Uint32 m_file_no; // Local_key
      Uint32 m_file_id; // DICT id
      Uint32 m_tablespace_id;
      Uint32 m_tablespace_version;
      Uint32 m_data_pages;
      Uint32 m_extent_pages;
      Uint32 m_extent_size;
      Uint32 m_extent_count;
      Uint32 m_extent_headers_per_page;
      Uint32 m_extent_header_words;
      Uint32 m_extent_header_bits_per_page;
    };
    
    struct Extent_header 
    {
      Uint32 m_table;
      union 
      {
	Uint32 m_fragment_id;
	Uint32 m_next_free_extent;
      };
      Uint32 m_page_bitmask[1]; // (BitsPerPage*ExtentSize)/(32*PageSize)
      Uint32 get_free_bits(Uint32 page) const;
      Uint32 get_free_word_offset(Uint32 page) const;
      void update_free_bits(Uint32 page, Uint32 bit);
      bool check_free(Uint32 extent_size) const ;
    };
    
    STATIC_CONST( EXTENT_HEADER_BITMASK_BITS_PER_PAGE = 4 );
    STATIC_CONST( EXTENT_HEADER_FIXED_WORDS = (sizeof(Extent_header)>>2) - 1);
    static Uint32 extent_header_words(Uint32 extent_size_in_pages);
    
    struct Extent_page
    {
      struct Page_header m_page_header;
      Extent_header m_extents[1];
      
      Extent_header* get_header(Uint32 extent_no, Uint32 extent_size);
    };
    
    STATIC_CONST( EXTENT_PAGE_WORDS = NDB_PAGE_SIZE_WORDS - NDB_PAGE_HEADER_WORDS );
    
    struct Data_page 
    {
      struct Page_header m_page_header;
    };
  };

  struct Undofile 
  {
    struct Zero_page
    {
      struct Zero_page_header m_page_header;
      Uint32 m_file_id;
      Uint32 m_logfile_group_id;
      Uint32 m_logfile_group_version;
      Uint32 m_undo_pages;
    };
    struct Undo_page 
    {
      struct Page_header m_page_header;
      Uint32 m_words_used;
      Uint32 m_data[1];
    };

    struct Undo_entry
    {
      Uint32 m_file_no;
      Uint32 m_page_no;
      struct 
      {
	Uint32 m_len_offset;
	Uint32 m_data[1];
      } m_changes[1];
      Uint32 m_length; // [ 16-bit type | 16 bit length of entry ]
    };

    enum Undo_type {
      UNDO_LCP_FIRST  = 1 // First LCP record with specific lcp id
      ,UNDO_LCP = 2       // LCP Start
      
      /**
       * TUP Undo record
       */
      ,UNDO_TUP_ALLOC  = 3
      ,UNDO_TUP_UPDATE = 4
      ,UNDO_TUP_FREE   = 5
      ,UNDO_TUP_CREATE = 6

      ,UNDO_END        = 0x7FFF 
      ,UNDO_NEXT_LSN   = 0x8000
    };

    struct Undo_lcp
    {
      Uint32 m_lcp_id;
      Uint32 m_type_length; // 16 bit type, 16 bit length
    };
  };
  STATIC_CONST( UNDO_PAGE_WORDS = NDB_PAGE_SIZE_WORDS - NDB_PAGE_HEADER_WORDS - 1);
};


/**
 * Compute size of extent header in words
 */
inline Uint32 
File_formats::Datafile::extent_header_words(Uint32 extent_size_in_pages)
{
  return EXTENT_HEADER_FIXED_WORDS + 
    ((extent_size_in_pages * EXTENT_HEADER_BITMASK_BITS_PER_PAGE + 31) >> 5);
}

inline
File_formats::Datafile::Extent_header*
File_formats::Datafile::Extent_page::get_header(Uint32 no, Uint32 extent_size)
{
  Uint32 * tmp = (Uint32*)m_extents;
  tmp += no*File_formats::Datafile::extent_header_words(extent_size);
  return (Extent_header*)tmp;
}

inline
Uint32
File_formats::Datafile::Extent_header::get_free_bits(Uint32 page) const
{
  return ((m_page_bitmask[page >> 3] >> ((page & 7) << 2))) & 15;
}

inline
Uint32
File_formats::Datafile::Extent_header::get_free_word_offset(Uint32 page) const
{
  return page >> 3;
}

inline
void
File_formats::Datafile::Extent_header::update_free_bits(Uint32 page, 
							Uint32 bit)
{
  Uint32 shift = (page & 7) << 2;
  Uint32 mask = (15 << shift);
  Uint32 org = m_page_bitmask[page >> 3];
  m_page_bitmask[page >> 3] = (org & ~mask) | (bit << shift);
}

inline
bool
File_formats::Datafile::Extent_header::check_free(Uint32 extent_size) const 
{
  Uint32 words = (extent_size * EXTENT_HEADER_BITMASK_BITS_PER_PAGE + 31) >> 5;
  Uint32 sum = 0;
  for(; words; words--)
    sum |= m_page_bitmask[words-1];

  if(sum & 0x7777)
    return false;
  
  return true;
}

#include <NdbOut.hpp>
NdbOut& operator<<(NdbOut& out, const File_formats::Zero_page_header&);
NdbOut& operator<<(NdbOut& out, const File_formats::Datafile::Zero_page&);
NdbOut& operator<<(NdbOut& out, const File_formats::Undofile::Zero_page&);

#endif

--- New file ---
+++ storage/ndb/src/kernel/blocks/lgman.cpp	05/10/10 21:27:20
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "lgman.hpp"
#include "diskpage.hpp"
#include <signaldata/FsRef.hpp>
#include <signaldata/FsConf.hpp>
#include <signaldata/FsOpenReq.hpp>
#include <signaldata/FsCloseReq.hpp>
#include <signaldata/CreateFilegroupImpl.hpp>
#include <signaldata/DropFilegroupImpl.hpp>
#include <signaldata/FsReadWriteReq.hpp>
#include <signaldata/LCP.hpp>
#include <signaldata/SumaImpl.hpp>
#include <signaldata/LgmanContinueB.hpp>
#include "ndbfs/Ndbfs.hpp"
#include "dbtup/Dbtup.hpp"

#include <EventLogger.hpp>
extern EventLogger g_eventLogger;

/**
 * ---<a>-----<b>-----<c>-----<d>---> (time)
 *
 * <a> = start of lcp 1
 * <b> = stop of lcp 1
 * <c> = start of lcp 2
 * <d> = stop of lcp 2
 *
 * If ndb crashes before <d>
 *   the entire undo log from crash point until <a> has to be applied
 *
 * at <d> the undo log can be cut til <c> 
 */

#define DEBUG_UNDO_EXECUTION 0
#define DEBUG_SEARCH_LOG_HEAD 0

Lgman::Lgman(const Configuration & conf) :
  SimulatedBlock(LGMAN, conf),
  m_logfile_group_list(m_logfile_group_pool),
  m_logfile_group_hash(m_logfile_group_pool)
{
  BLOCK_CONSTRUCTOR(Lgman);
  
  // Add received signals
  addRecSignal(GSN_STTOR, &Lgman::execSTTOR);
  addRecSignal(GSN_READ_CONFIG_REQ, &Lgman::execREAD_CONFIG_REQ);
  addRecSignal(GSN_DUMP_STATE_ORD, &Lgman::execDUMP_STATE_ORD);
  addRecSignal(GSN_CONTINUEB, &Lgman::execCONTINUEB);

  addRecSignal(GSN_CREATE_FILE_REQ, &Lgman::execCREATE_FILE_REQ);
  addRecSignal(GSN_CREATE_FILEGROUP_REQ, &Lgman::execCREATE_FILEGROUP_REQ);

  addRecSignal(GSN_DROP_FILE_REQ, &Lgman::execDROP_FILE_REQ);
  addRecSignal(GSN_DROP_FILEGROUP_REQ, &Lgman::execDROP_FILEGROUP_REQ);

  addRecSignal(GSN_FSWRITEREQ, &Lgman::execFSWRITEREQ);
  addRecSignal(GSN_FSWRITEREF, &Lgman::execFSWRITEREF, true);
  addRecSignal(GSN_FSWRITECONF, &Lgman::execFSWRITECONF);

  addRecSignal(GSN_FSOPENREF, &Lgman::execFSOPENREF, true);
  addRecSignal(GSN_FSOPENCONF, &Lgman::execFSOPENCONF);

  addRecSignal(GSN_FSCLOSECONF, &Lgman::execFSCLOSECONF);
  
  addRecSignal(GSN_FSREADREF, &Lgman::execFSREADREF, true);
  addRecSignal(GSN_FSREADCONF, &Lgman::execFSREADCONF);

  addRecSignal(GSN_LCP_FRAG_ORD, &Lgman::execLCP_FRAG_ORD);
  addRecSignal(GSN_END_LCP_REQ, &Lgman::execEND_LCP_REQ);
  addRecSignal(GSN_SUB_GCP_COMPLETE_REP, &Lgman::execSUB_GCP_COMPLETE_REP);
  addRecSignal(GSN_START_RECREQ, &Lgman::execSTART_RECREQ);
  
  addRecSignal(GSN_END_LCP_CONF, &Lgman::execEND_LCP_CONF);
  
  m_last_lsn = 0;
  m_logfile_group_pool.setSize(10);
  m_logfile_group_hash.setSize(10);
  m_file_pool.setSize(10);
  m_data_buffer_pool.setSize(10);
  m_log_waiter_pool.setSize(10000);
}
  
Lgman::~Lgman()
{
}

BLOCK_FUNCTIONS(Lgman)

void 
Lgman::execREAD_CONFIG_REQ(Signal* signal)
{
  jamEntry();

  const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr();

  Uint32 ref = req->senderRef;
  Uint32 senderData = req->senderData;

  const ndb_mgm_configuration_iterator * p = 
    theConfiguration.getOwnConfigIterator();
  ndbrequire(p != 0);

  ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
  conf->senderRef = reference();
  conf->senderData = senderData;
  sendSignal(ref, GSN_READ_CONFIG_CONF, signal, 
	     ReadConfigConf::SignalLength, JBB);
}

void
Lgman::execSTTOR(Signal* signal) 
{
  jamEntry();                            

  const Uint32 startphase  = signal->theData[1];
  const Uint32 typeOfStart = signal->theData[7];

  sendSTTORRY(signal);
  
  return;
}//Lgman::execNDB_STTOR()

void
Lgman::sendSTTORRY(Signal* signal)
{
  signal->theData[0] = 0;
  signal->theData[3] = 1;
  signal->theData[4] = 2;
  signal->theData[5] = 3;
  signal->theData[6] = 4;
  signal->theData[7] = 5;
  signal->theData[8] = 6;
  signal->theData[9] = 255; // No more start phases from missra
  sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 10, JBB);
}

void
Lgman::execCONTINUEB(Signal* signal){
  jamEntry();

  Uint32 type= signal->theData[0];
  Uint32 ptrI = signal->theData[1];
  switch(type){
  case LgmanContinueB::FILTER_LOG:
    jam();
    break;
  case LgmanContinueB::CUT_LOG_TAIL:
  {
    jam();
    Ptr<Logfile_group> ptr;
    m_logfile_group_pool.getPtr(ptr, ptrI);
    cut_log_tail(signal, ptr);
    return;
  }
  case LgmanContinueB::FLUSH_LOG:
  {
    jam();
    Ptr<Logfile_group> ptr;
    m_logfile_group_pool.getPtr(ptr, ptrI);
    flush_log(signal, ptr);
    return;
  }
  case LgmanContinueB::PROCESS_LOG_BUFFER_WAITERS:
  {
    jam();
    Ptr<Logfile_group> ptr;
    m_logfile_group_pool.getPtr(ptr, ptrI);
    process_log_buffer_waiters(signal, ptr);
    return;
  }
  case LgmanContinueB::FIND_LOG_HEAD:
    jam();
    Ptr<Logfile_group> ptr;
    if(ptrI != RNIL)
    {
      m_logfile_group_pool.getPtr(ptr, ptrI);
      find_log_head(signal, ptr);
    }
    else
    {
      init_run_undo_log(signal);
    }
    return;
  case LgmanContinueB::EXECUTE_UNDO_RECORD:
    jam();
    execute_undo_record(signal);
    return;
  case LgmanContinueB::STOP_UNDO_LOG:
    jam();
    stop_run_undo_log(signal);
    return;
  case LgmanContinueB::READ_UNDO_LOG:
  {
    jam();
    Ptr<Logfile_group> ptr;
    m_logfile_group_pool.getPtr(ptr, ptrI);
    read_undo_log(signal, ptr);
    return;
  }
  case LgmanContinueB::PROCESS_LOG_SYNC_WAITERS:
  {
    jam();
    Ptr<Logfile_group> ptr;
    m_logfile_group_pool.getPtr(ptr, ptrI);
    process_log_sync_waiters(signal, ptr);
    return;
  }
  case LgmanContinueB::FORCE_LOG_SYNC:
  {
    jam();
    Ptr<Logfile_group> ptr;
    m_logfile_group_pool.getPtr(ptr, ptrI);
    force_log_sync(signal, ptr, signal->theData[2], signal->theData[3]);
    return;
  }
  case LgmanContinueB::DROP_FILEGROUP:
  {
    jam();
    Ptr<Logfile_group> ptr;
    m_logfile_group_pool.getPtr(ptr, ptrI);
    if (ptr.p->m_state & Logfile_group::LG_THREAD_MASK)
    {
      jam();
      sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 
			  signal->length());
      return;
    }
    Uint32 ref = signal->theData[2];
    Uint32 data = signal->theData[3];
    drop_filegroup_drop_files(signal, ptr, ref, data);
    return;
  }
  }
}

void
Lgman::execDUMP_STATE_ORD(Signal* signal){
  jamEntry();
  if(signal->theData[0] == 12001)
  {
    Ptr<Logfile_group> ptr;
    m_logfile_group_list.first(ptr);
    while(!ptr.isNull())
    {
      infoEvent("lfg %d state: %x fs: %d lsn "
		"[ last: %lld s(req): %lld s:ed: %lld lcp: %lld ] waiters: %d",
		ptr.p->m_logfile_group_id, ptr.p->m_state, 
		ptr.p->m_outstanding_fs,
		ptr.p->m_last_lsn, ptr.p->m_last_sync_req_lsn,
		ptr.p->m_last_synced_lsn, ptr.p->m_last_lcp_lsn,
		!ptr.p->m_log_sync_waiters.isEmpty());
      m_logfile_group_list.next(ptr);
    }
  }
}

void
Lgman::execCREATE_FILEGROUP_REQ(Signal* signal){
  jamEntry();
  CreateFilegroupImplReq* req= (CreateFilegroupImplReq*)signal->getDataPtr();

  Uint32 senderRef = req->senderRef;
  Uint32 senderData = req->senderData;
  
  Ptr<Logfile_group> ptr;
  CreateFilegroupImplRef::ErrorCode err = CreateFilegroupImplRef::NoError;
  do {
    if (m_logfile_group_hash.find(ptr, req->filegroup_id))
    {
      jam();
      err = CreateFilegroupImplRef::FilegroupAlreadyExists;
      break;
    }
    
    if (!m_logfile_group_pool.seize(ptr))
    {
      jam();
      err = CreateFilegroupImplRef::OutOfFilegroupRecords;
      break;
    }

    new (ptr.p) Logfile_group(req);
    
    if (!alloc_logbuffer_memory(ptr, req->logfile_group.buffer_size))
    {
      jam();
      err= CreateFilegroupImplRef::OutOfLogBufferMemory;
      m_logfile_group_pool.release(ptr);
      break;
    }
    
    m_logfile_group_hash.add(ptr);
    m_logfile_group_list.add(ptr);
    
    CreateFilegroupImplConf* conf= 
      (CreateFilegroupImplConf*)signal->getDataPtr();
    conf->senderData = senderData;
    conf->senderRef = reference();
    sendSignal(senderRef, GSN_CREATE_FILEGROUP_CONF, signal, 
	       CreateFilegroupImplConf::SignalLength, JBB);
    
    return;
  } while(0);
  
  CreateFilegroupImplRef* ref= (CreateFilegroupImplRef*)signal->getDataPtr();
  ref->senderData = senderData;
  ref->senderRef = reference();
  ref->errorCode = err;
  sendSignal(senderRef, GSN_CREATE_FILEGROUP_REF, signal, 
	     CreateFilegroupImplRef::SignalLength, JBB);
}

void
Lgman::execDROP_FILEGROUP_REQ(Signal* signal)
{
  jamEntry();

  jamEntry();

  Uint32 errorCode = 0;
  DropFilegroupImplReq req = *(DropFilegroupImplReq*)signal->getDataPtr();  
  do 
  {
    Ptr<Logfile_group> ptr;
    if (!m_logfile_group_hash.find(ptr, req.filegroup_id))
    {
      errorCode = DropFilegroupImplRef::NoSuchFilegroup;
      break;
    }
    
    if (ptr.p->m_version != req.filegroup_version)
    {
      errorCode = DropFilegroupImplRef::InvalidFilegroupVersion;
      break;
    }
    
    switch(req.requestInfo){
    case DropFilegroupImplReq::Prepare:
      break;
    case DropFilegroupImplReq::Commit:
      m_logfile_group_list.remove(ptr);
      ptr.p->m_state |= Logfile_group::LG_DROPPING;
      signal->theData[0] = LgmanContinueB::DROP_FILEGROUP;
      signal->theData[1] = ptr.i;
      signal->theData[2] = req.senderRef;
      signal->theData[3] = req.senderData;
      sendSignal(reference(), GSN_CONTINUEB, signal, 4, JBB);
      return;
    case DropFilegroupImplReq::Abort:
      break;
    default:
      ndbrequire(false);
    }
  } while(0);
  
  if (errorCode)
  {
    DropFilegroupImplRef* ref = 
      (DropFilegroupImplRef*)signal->getDataPtrSend();
    ref->senderRef = reference();
    ref->senderData = req.senderData;
    ref->errorCode = errorCode;
    sendSignal(req.senderRef, GSN_DROP_FILEGROUP_REF, signal,
	       DropFilegroupImplRef::SignalLength, JBB);
  }
  else
  {
    DropFilegroupImplConf* conf = 
      (DropFilegroupImplConf*)signal->getDataPtrSend();
    conf->senderRef = reference();
    conf->senderData = req.senderData;
    sendSignal(req.senderRef, GSN_DROP_FILEGROUP_CONF, signal,
	       DropFilegroupImplConf::SignalLength, JBB);
  }
}

void
Lgman::drop_filegroup_drop_files(Signal* signal,
				 Ptr<Logfile_group> ptr,
				 Uint32 ref, Uint32 data)
{
  jam();
  ndbassert(! (ptr.p->m_state & Logfile_group::LG_THREAD_MASK));
  ndbrequire(ptr.p->m_meta_files.isEmpty());
  ndbrequire(ptr.p->m_outstanding_fs == 0);

  LocalDLFifoList<Undofile> list(m_file_pool, ptr.p->m_files);
  Ptr<Undofile> file_ptr;

  if (list.first(file_ptr))
  {
    jam();
    ndbrequire(! (file_ptr.p->m_state & Undofile::FS_OUTSTANDING));
    file_ptr.p->m_create.m_senderRef = ref;
    file_ptr.p->m_create.m_senderData = data;
    create_file_abort(signal, ptr, file_ptr);
    return;
  }

  free_logbuffer_memory(ptr);
  m_logfile_group_hash.release(ptr);
  DropFilegroupImplConf *conf = (DropFilegroupImplConf*)signal->getDataPtr();  
  conf->senderData = data;
  conf->senderRef = reference();
  sendSignal(ref, GSN_DROP_FILEGROUP_CONF, signal, 
	     DropFilegroupImplConf::SignalLength, JBB);
}

void
Lgman::execCREATE_FILE_REQ(Signal* signal){
  jamEntry();
  CreateFileImplReq* req= (CreateFileImplReq*)signal->getDataPtr();
  
  Uint32 senderRef = req->senderRef;
  Uint32 senderData = req->senderData;
  Uint32 requestInfo = req->requestInfo;
  
  Ptr<Logfile_group> ptr;
  CreateFileImplRef::ErrorCode err = CreateFileImplRef::NoError;
  do {
    if (!m_logfile_group_hash.find(ptr, req->filegroup_id))
    {
      jam();
      err = CreateFileImplRef::InvalidFilegroup;
      break;
    }

    if (ptr.p->m_version != req->filegroup_version)
    {
      jam();
      err = CreateFileImplRef::InvalidFilegroupVersion;
      break;
    }

    Ptr<Undofile> file_ptr;
    switch(requestInfo){
    case CreateFileImplReq::Commit:
    {
      ndbrequire(find_file_by_id(file_ptr, ptr.p->m_meta_files, req->file_id));
      file_ptr.p->m_create.m_senderRef = req->senderRef;
      file_ptr.p->m_create.m_senderData = req->senderData;
      create_file_commit(signal, ptr, file_ptr);
      return;
    }
    case CreateFileImplReq::Abort:
    {
      Uint32 senderRef = req->senderRef;
      Uint32 senderData = req->senderData;
      if (find_file_by_id(file_ptr, ptr.p->m_meta_files, req->file_id))
      {
	file_ptr.p->m_create.m_senderRef = senderRef;
	file_ptr.p->m_create.m_senderData = senderData;
	create_file_abort(signal, ptr, file_ptr);
      }
      else
      {
	CreateFileImplConf* conf= (CreateFileImplConf*)signal->getDataPtr();
	conf->senderData = senderData;
	conf->senderRef = reference();
	sendSignal(senderRef, GSN_CREATE_FILE_CONF, signal, 
		   CreateFileImplConf::SignalLength, JBB);
	return;
      }
      return;
    }
    default: // prepare
      break;
    }
    
    if (!m_file_pool.seize(file_ptr))
    {
      jam();
      err = CreateFileImplRef::OutOfFileRecords;
      break;
    }
    
    new (file_ptr.p) Undofile(req, ptr.i);
    LocalDLFifoList<Undofile> tmp(m_file_pool, ptr.p->m_meta_files);
    tmp.add(file_ptr);
    
    open_file(signal, file_ptr, req->requestInfo);
    return;
  } while(0);
  
  CreateFileImplRef* ref= (CreateFileImplRef*)signal->getDataPtr();
  ref->senderData = senderData;
  ref->senderRef = reference();
  ref->errorCode = err;
  sendSignal(senderRef, GSN_CREATE_FILE_REF, signal, 
	     CreateFileImplRef::SignalLength, JBB);
}

void
Lgman::open_file(Signal* signal, Ptr<Undofile> ptr, Uint32 requestInfo)
{
  FsOpenReq* req = (FsOpenReq*)signal->getDataPtrSend();
  req->userReference = reference();
  req->userPointer = ptr.i;
  
  memset(req->fileNumber, 0, sizeof(req->fileNumber));
  FsOpenReq::setVersion(req->fileNumber, 4); // Version 4 = specified filename

  req->fileFlags = 0;
  req->fileFlags |= FsOpenReq::OM_READWRITE;
  req->fileFlags |= FsOpenReq::OM_DIRECT;
  req->fileFlags |= FsOpenReq::OM_SYNC;
  switch(requestInfo){
  case CreateFileImplReq::Create:
    req->fileFlags |= FsOpenReq::OM_CREATE_IF_NONE;
    req->fileFlags |= FsOpenReq::OM_INIT;
    ptr.p->m_state = Undofile::FS_CREATING;
    break;
  case CreateFileImplReq::CreateForce:
    req->fileFlags |= FsOpenReq::OM_CREATE;
    req->fileFlags |= FsOpenReq::OM_INIT;
    ptr.p->m_state = Undofile::FS_CREATING;
    break;
  case CreateFileImplReq::Open:
    req->fileFlags |= FsOpenReq::OM_CHECK_SIZE;
    ptr.p->m_state = Undofile::FS_OPENING;
    break;
  default:
    ndbrequire(false);
  }

  req->page_size = File_formats::NDB_PAGE_SIZE;
  Uint64 size = (Uint64)ptr.p->m_file_size * (Uint64)File_formats::NDB_PAGE_SIZE;
  req->file_size_hi = size >> 32;
  req->file_size_lo = size & 0xFFFFFFFF;

  // Forward filename
  sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, FsOpenReq::SignalLength, JBB);
}

void
Lgman::execFSWRITEREQ(Signal* signal)
{
  jamEntry();
  Ptr<Undofile> ptr;
  Ptr<GlobalPage> page_ptr;
  FsReadWriteReq* req= (FsReadWriteReq*)signal->getDataPtr();
  
  m_file_pool.getPtr(ptr, req->userPointer);
  m_global_page_pool.getPtr(page_ptr, req->data.pageData[0]);

  if (req->varIndex == 0)
  {
    jam();
    File_formats::Undofile::Zero_page* page = 
      (File_formats::Undofile::Zero_page*)page_ptr.p;
    page->m_page_header.init(File_formats::FT_Undofile, 
			     getOwnNodeId(),
			     ndbGetOwnVersion(),
			     time(0));
    page->m_file_id = ptr.p->m_file_id;
    page->m_logfile_group_id = ptr.p->m_create.m_logfile_group_id;
    page->m_logfile_group_version = ptr.p->m_create.m_logfile_group_version;
    page->m_undo_pages = ptr.p->m_file_size - 1; // minus zero page
  }
  else
  {
    jam();
    File_formats::Undofile::Undo_page* page = 
      (File_formats::Undofile::Undo_page*)page_ptr.p;
    page->m_page_header.m_page_lsn_hi = 0;
    page->m_page_header.m_page_lsn_lo = 0;
    page->m_page_header.m_page_type = File_formats::PT_Undopage;
    page->m_words_used = 0;
  }
}

void
Lgman::execFSOPENREF(Signal* signal)
{
  jamEntry();

  Ptr<Undofile> ptr;  
  Ptr<Logfile_group> lg_ptr;
  FsRef* ref = (FsRef*)signal->getDataPtr();

  Uint32 errCode = ref->errorCode;
  Uint32 osErrCode = ref->osErrorCode;

  m_file_pool.getPtr(ptr, ref->userPointer);
  m_logfile_group_pool.getPtr(lg_ptr, ptr.p->m_logfile_group_ptr_i);

  {
    CreateFileImplRef* ref= (CreateFileImplRef*)signal->getDataPtr();
    ref->senderData = ptr.p->m_create.m_senderData;
    ref->senderRef = reference();
    ref->errorCode = CreateFileImplRef::FileError;
    ref->fsErrCode = errCode;
    ref->osErrCode = osErrCode;
    sendSignal(ptr.p->m_create.m_senderRef, GSN_CREATE_FILE_REF, signal, 
	       CreateFileImplRef::SignalLength, JBB);
  }

  LocalDLFifoList<Undofile> meta(m_file_pool, lg_ptr.p->m_meta_files);
  meta.release(ptr);
}

#define HEAD 0
#define TAIL 1

void
Lgman::execFSOPENCONF(Signal* signal)
{
  jamEntry();
  Ptr<Undofile> ptr;  

  FsConf* conf = (FsConf*)signal->getDataPtr();
  
  Uint32 fd = conf->filePointer;
  m_file_pool.getPtr(ptr, conf->userPointer);

  ptr.p->m_fd = fd;

  {
    Uint32 senderRef = ptr.p->m_create.m_senderRef;
    Uint32 senderData = ptr.p->m_create.m_senderData;
    
    CreateFileImplConf* conf= (CreateFileImplConf*)signal->getDataPtr();
    conf->senderData = senderData;
    conf->senderRef = reference();
    sendSignal(senderRef, GSN_CREATE_FILE_CONF, signal, 
	       CreateFileImplConf::SignalLength, JBB);
  }
}

bool 
Lgman::find_file_by_id(Ptr<Undofile>& ptr, 
		       DLFifoList<Undofile>::Head& head, Uint32 id)
{
  LocalDLFifoList<Undofile> list(m_file_pool, head);
  for(list.first(ptr); !ptr.isNull(); list.next(ptr))
    if(ptr.p->m_file_id == id)
      return true;
  return false;
}

void
Lgman::create_file_commit(Signal* signal, 
			  Ptr<Logfile_group> lg_ptr, 
			  Ptr<Undofile> ptr)
{
  Uint32 senderRef = ptr.p->m_create.m_senderRef;
  Uint32 senderData = ptr.p->m_create.m_senderData;

  bool first= false;
  if(ptr.p->m_state == Undofile::FS_CREATING)
  {
    jam();
    LocalDLFifoList<Undofile> free(m_file_pool, lg_ptr.p->m_files);
    LocalDLFifoList<Undofile> meta(m_file_pool, lg_ptr.p->m_meta_files);
    first= free.isEmpty();
    meta.remove(ptr);
    if(!first)
    {
      /**
       * Add log file next after current head
       */
      Ptr<Undofile> curr;
      m_file_pool.getPtr(curr, lg_ptr.p->m_file_pos[HEAD].m_ptr_i);
      if(free.next(curr))
	free.insert(ptr, curr); // inserts before (that's why the extra next)
      else
	free.add(ptr);

      ptr.p->m_state = Undofile::FS_ONLINE | Undofile::FS_EMPTY;
    }
    else
    {
      /**
       * First file isn't empty as it can be written to at any time
       */
      free.add(ptr);
      ptr.p->m_state = Undofile::FS_ONLINE;
      lg_ptr.p->m_state |= Logfile_group::LG_FLUSH_THREAD;
      signal->theData[0] = LgmanContinueB::FLUSH_LOG;
      signal->theData[1] = lg_ptr.i;
      sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
    }
  }
  else
  {
    ptr.p->m_state = Undofile::FS_SORTING;
  }
  
  ptr.p->m_online.m_outstanding = 0;
  
  Uint64 add= ptr.p->m_file_size - 1;
  lg_ptr.p->m_free_file_words += add * File_formats::UNDO_PAGE_WORDS;

  if(first)
  {
    jam();
    
    Buffer_idx tmp= { ptr.i, 0 };
    lg_ptr.p->m_file_pos[HEAD] = lg_ptr.p->m_file_pos[TAIL] = tmp;
    
    /**
     * Init log tail pointer
     */
    lg_ptr.p->m_tail_pos[0] = tmp;
    lg_ptr.p->m_tail_pos[1] = tmp;
    lg_ptr.p->m_tail_pos[2] = tmp;
    lg_ptr.p->m_next_reply_ptr_i = ptr.i;
  }

  validate_logfile_group(lg_ptr, "create_file_commit");

  CreateFileImplConf* conf= (CreateFileImplConf*)signal->getDataPtr();
  conf->senderData = senderData;
  conf->senderRef = reference();
  sendSignal(senderRef, GSN_CREATE_FILE_CONF, signal, 
	     CreateFileImplConf::SignalLength, JBB);
}

void
Lgman::create_file_abort(Signal* signal, 
			 Ptr<Logfile_group> lg_ptr, 
			 Ptr<Undofile> ptr)
{
  if (ptr.p->m_fd == RNIL)
  {
    ((FsConf*)signal->getDataPtr())->userPointer = ptr.i;
    execFSCLOSECONF(signal);
    return;
  }

  FsCloseReq *req= (FsCloseReq*)signal->getDataPtrSend();
  req->filePointer = ptr.p->m_fd;
  req->userReference = reference();
  req->userPointer = ptr.i;
  req->fileFlag = 0;
  FsCloseReq::setRemoveFileFlag(req->fileFlag, true);
  
  sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 
	     FsCloseReq::SignalLength, JBB);
}

void
Lgman::execFSCLOSECONF(Signal* signal)
{
  Ptr<Undofile> ptr;
  Ptr<Logfile_group> lg_ptr;
  Uint32 ptrI = ((FsConf*)signal->getDataPtr())->userPointer;
  m_file_pool.getPtr(ptr, ptrI);
  
  Uint32 senderRef = ptr.p->m_create.m_senderRef;
  Uint32 senderData = ptr.p->m_create.m_senderData;
  
  m_logfile_group_pool.getPtr(lg_ptr, ptr.p->m_logfile_group_ptr_i);

  if (lg_ptr.p->m_state & Logfile_group::LG_DROPPING)
  {
    jam();
    {
      LocalDLFifoList<Undofile> list(m_file_pool, lg_ptr.p->m_files);
      list.release(ptr);
    }
    drop_filegroup_drop_files(signal, lg_ptr, senderRef, senderData);
  }
  else
  {
    jam();
    LocalDLFifoList<Undofile> list(m_file_pool, lg_ptr.p->m_meta_files);
    list.release(ptr);

    CreateFileImplConf* conf= (CreateFileImplConf*)signal->getDataPtr();
    conf->senderData = senderData;
    conf->senderRef = reference();
    sendSignal(senderRef, GSN_CREATE_FILE_CONF, signal, 
	       CreateFileImplConf::SignalLength, JBB);
  }
}

void
Lgman::execDROP_FILE_REQ(Signal* signal)
{
  jamEntry();
  ndbrequire(false);
}

#define CONSUMER 0
#define PRODUCER 1

Lgman::Logfile_group::Logfile_group(const CreateFilegroupImplReq* req)
{
  m_logfile_group_id = req->filegroup_id;
  m_version = req->filegroup_version;
  m_state = LG_ONLINE;

  m_last_lsn = 0;
  m_last_synced_lsn = 0;
  m_last_sync_req_lsn = 0;
  m_last_read_lsn = 0;
  m_file_pos[0].m_ptr_i= m_file_pos[1].m_ptr_i = RNIL;

  m_free_file_words = 0;
  m_free_buffer_words = 0;
  m_pos[CONSUMER].m_current_page.m_ptr_i = RNIL;// { m_buffer_pages, idx }
  m_pos[CONSUMER].m_current_pos.m_ptr_i = RNIL; // { page ptr.i, m_words_used}
  m_pos[PRODUCER].m_current_page.m_ptr_i = RNIL;// { m_buffer_pages, idx }
  m_pos[PRODUCER].m_current_pos.m_ptr_i = RNIL; // { page ptr.i, m_words_used}

  m_tail_pos[2].m_ptr_i= RNIL;
  m_tail_pos[2].m_idx= ~0;
  
  m_tail_pos[0] = m_tail_pos[1] = m_tail_pos[2];
}

bool
Lgman::alloc_logbuffer_memory(Ptr<Logfile_group> ptr, Uint32 bytes)
{
  /**
   * TODO use buddy allocator
   */
  Uint32 pages= (((bytes + 3) >> 2) + File_formats::NDB_PAGE_SIZE_WORDS - 1)
    / File_formats::NDB_PAGE_SIZE_WORDS;
  Uint32 requested= pages;
  {
    Page_map map(m_data_buffer_pool, ptr.p->m_buffer_pages);
    while(pages)
    {
      Ptr<GlobalPage> page;
      if(m_global_page_pool.seize(page))
      {
	Buffer_idx range;
	range.m_ptr_i= page.i;
	range.m_idx = 1;
	while(pages >range.m_idx && m_global_page_pool.seizeId(page, page.i+1))
	  range.m_idx++;
	
	ndbrequire(map.append((Uint32*)&range, 2));
	pages -= range.m_idx;
      }
      else
      {
	break;
      }
    }
  }

  if(2*pages > requested)
  {
    // less than half allocated
    free_logbuffer_memory(ptr);
    return false;
  }
  
  if(pages != 0)
  {
    warningEvent("Allocated %d pages for log buffer space, logfile_group: %d"
		 " , requested %d pages", 
		 (requested-pages), ptr.p->m_logfile_group_id, requested);
  }
  
  init_logbuffer_pointers(ptr);
  return true;
}

void
Lgman::init_logbuffer_pointers(Ptr<Logfile_group> ptr)
{
  Page_map map(m_data_buffer_pool, ptr.p->m_buffer_pages);
  Page_map::Iterator it;
  union {
    Uint32 tmp[2];
    Buffer_idx range;
  };
  
  map.first(it);
  tmp[0] = *it.data;
  ndbrequire(map.next(it));
  tmp[1] = *it.data;
  
  ptr.p->m_pos[CONSUMER].m_current_page.m_ptr_i = 0;      // Index in page map
  ptr.p->m_pos[CONSUMER].m_current_page.m_idx = range.m_idx - 1;// left range
  ptr.p->m_pos[CONSUMER].m_current_pos.m_ptr_i = range.m_ptr_i; // Which page
  ptr.p->m_pos[CONSUMER].m_current_pos.m_idx = 0;               // Page pos
  
  ptr.p->m_pos[PRODUCER].m_current_page.m_ptr_i = 0;      // Index in page map
  ptr.p->m_pos[PRODUCER].m_current_page.m_idx = range.m_idx - 1;// left range
  ptr.p->m_pos[PRODUCER].m_current_pos.m_ptr_i = range.m_ptr_i; // Which page
  ptr.p->m_pos[PRODUCER].m_current_pos.m_idx = 0;               // Page pos

  Uint32 pages= range.m_idx;
  while(map.next(it))
  {
    tmp[0] = *it.data;
    ndbrequire(map.next(it));
    tmp[1] = *it.data;
    pages += range.m_idx;
  }
  
  ptr.p->m_free_buffer_words = pages * File_formats::UNDO_PAGE_WORDS;
}

Uint32
Lgman::compute_free_file_pages(Ptr<Logfile_group> ptr)
{
  Buffer_idx head= ptr.p->m_file_pos[HEAD];
  Buffer_idx tail= ptr.p->m_file_pos[TAIL];
  Uint32 pages = 0;
  if (head.m_ptr_i == tail.m_ptr_i && head.m_idx < tail.m_idx)
  {
    pages += tail.m_idx - head.m_idx;
  }
  else
  {
    Ptr<Undofile> file;
    m_file_pool.getPtr(file, head.m_ptr_i);
    LocalDLFifoList<Undofile> list(m_file_pool, ptr.p->m_files);
    
    do 
    {
      pages += (file.p->m_file_size - head.m_idx - 1);
      if(!list.next(file))
	list.first(file);
      head.m_idx = 0;
    } while(file.i != tail.m_ptr_i);
    
    pages += tail.m_idx - head.m_idx;
  }
  return pages;
}

void
Lgman::free_logbuffer_memory(Ptr<Logfile_group> ptr)
{
  union {
    Uint32 tmp[2];
    Buffer_idx range;
  };

  Page_map map(m_data_buffer_pool, ptr.p->m_buffer_pages);

  Page_map::Iterator it;
  map.first(it);
  while(!it.isNull())
  {
    tmp[0] = *it.data;
    ndbrequire(map.next(it));
    tmp[1] = *it.data;
    while(range.m_idx)
    {
      m_global_page_pool.release(range.m_ptr_i);
      range.m_ptr_i++;
      range.m_idx--;
    }
    map.next(it);
  }
  map.release();
}

Lgman::Undofile::Undofile(const struct CreateFileImplReq* req, Uint32 ptrI)
{
  m_fd = RNIL;
  m_file_id = req->file_id;
  m_logfile_group_ptr_i= ptrI;
  
  Uint64 pages = req->file_size_hi;
  pages = (pages << 32) | req->file_size_lo;
  pages /= GLOBAL_PAGE_SIZE;
  m_file_size = pages;

  m_create.m_senderRef = req->senderRef; // During META
  m_create.m_senderData = req->senderData; // During META
  m_create.m_logfile_group_id = req->filegroup_id;
}

Logfile_client::Logfile_client(SimulatedBlock* block, 
			       Lgman* lgman, Uint32 logfile_group_id)
{
  m_block= block->number();
  m_lgman= lgman;
  m_logfile_group_id= logfile_group_id;
}

int
Logfile_client::sync_lsn(Signal* signal, 
			 Uint64 lsn, Request* req, Uint32 flags)
{
  Ptr<Lgman::Logfile_group> ptr;
  if(m_lgman->m_logfile_group_list.first(ptr))
  {
    if(ptr.p->m_last_synced_lsn >= lsn)
    {
      return 1;
    }

    bool empty= false;
    Ptr<Lgman::Log_waiter> wait;
    {
      LocalDLFifoList<Lgman::Log_waiter> 
	list(m_lgman->m_log_waiter_pool, ptr.p->m_log_sync_waiters);
      
      empty= list.isEmpty();
      if(!list.seize(wait))
	return -1;
      
      wait.p->m_block= m_block;
      wait.p->m_sync_lsn= lsn;
      memcpy(&wait.p->m_callback, &req->m_callback, 
	     sizeof(SimulatedBlock::Callback));
    }

    if(ptr.p->m_last_sync_req_lsn < lsn && 
       ! (ptr.p->m_state & Lgman::Logfile_group::LG_FORCE_SYNC_THREAD))
    { 
      ptr.p->m_state |= Lgman::Logfile_group::LG_FORCE_SYNC_THREAD;
      signal->theData[0] = LgmanContinueB::FORCE_LOG_SYNC;
      signal->theData[1] = ptr.i;
      signal->theData[2] = lsn >> 32;
      signal->theData[3] = lsn & 0xFFFFFFFF;
      m_lgman->sendSignalWithDelay(m_lgman->reference(), 
				   GSN_CONTINUEB, signal, 10, 4);
    }
    return 0;
  }
  return -1;
}

void
Lgman::force_log_sync(Signal* signal, 
		      Ptr<Logfile_group> ptr, 
		      Uint32 lsn_hi, Uint32 lsn_lo)
{
  LocalDLFifoList<Lgman::Log_waiter> 
    list(m_log_waiter_pool, ptr.p->m_log_sync_waiters);
  Uint64 force_lsn = lsn_hi; force_lsn <<= 32; force_lsn += lsn_lo;

  if(ptr.p->m_last_sync_req_lsn < force_lsn)
  {
    /**
     * Do force
     */
    Buffer_idx pos= ptr.p->m_pos[PRODUCER].m_current_pos;
    GlobalPage *page = m_global_page_pool.getPtr(pos.m_ptr_i);
  
    Uint32 free= File_formats::UNDO_PAGE_WORDS - pos.m_idx;
    if(pos.m_idx) // don't flush empty page...
    {
      Uint64 lsn= ptr.p->m_last_lsn - 1;
      
      File_formats::Undofile::Undo_page* undo= 
	(File_formats::Undofile::Undo_page*)page;
      undo->m_page_header.m_page_lsn_lo = lsn & 0xFFFFFFFF;
      undo->m_page_header.m_page_lsn_hi = lsn >> 32;
      undo->m_words_used= File_formats::UNDO_PAGE_WORDS - free;
      
      /**
       * Update free space with extra NOOP
       */
      ndbassert(ptr.p->m_free_file_words >= free);
      ndbassert(ptr.p->m_free_buffer_words >= free);
      ptr.p->m_free_file_words -= free;
      ptr.p->m_free_buffer_words -= free;
      
      validate_logfile_group(ptr, "force_log_sync");

      next_page(ptr.p, PRODUCER);
      ptr.p->m_pos[PRODUCER].m_current_pos.m_idx = 0;
    }
  }

  
  Ptr<Lgman::Log_waiter> last;
  if(list.last(last) && 
     last.p->m_sync_lsn > force_lsn && 
     ptr.p->m_last_sync_req_lsn < last.p->m_sync_lsn)
  {
    ndbassert(ptr.p->m_state & Lgman::Logfile_group::LG_FORCE_SYNC_THREAD);
    signal->theData[0] = LgmanContinueB::FORCE_LOG_SYNC;
    signal->theData[1] = ptr.i;
    signal->theData[2] = last.p->m_sync_lsn >> 32;
    signal->theData[3] = last.p->m_sync_lsn & 0xFFFFFFFF;    
    sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 10, 4);
  }
  else
  {
    ptr.p->m_state &= ~(Uint32)Lgman::Logfile_group::LG_FORCE_SYNC_THREAD;
  }
}

void
Lgman::process_log_sync_waiters(Signal* signal, Ptr<Logfile_group> ptr)
{
  LocalDLFifoList<Log_waiter> 
    list(m_log_waiter_pool, ptr.p->m_log_sync_waiters);

  if(list.isEmpty())
  {
    return;
  }

  bool removed= false;
  Ptr<Log_waiter> waiter;
  list.first(waiter);

  if(waiter.p->m_sync_lsn <= ptr.p->m_last_synced_lsn)
  {
    removed= true;
    Uint32 block = waiter.p->m_block;
    SimulatedBlock* b = globalData.getBlock(block);
    b->execute(signal, waiter.p->m_callback, 0);

    list.release(waiter);
  }
  
  if(removed && !list.isEmpty())
  {
    ptr.p->m_state |= Logfile_group::LG_SYNC_WAITERS_THREAD;
    signal->theData[0] = LgmanContinueB::PROCESS_LOG_SYNC_WAITERS;
    signal->theData[1] = ptr.i;
    sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
  }
  else
  {
    ptr.p->m_state &= ~(Uint32)Logfile_group::LG_SYNC_WAITERS_THREAD;
  }
}


Uint32*
Lgman::get_log_buffer(Ptr<Logfile_group> ptr, Uint32 sz)
{
  GlobalPage *page;
  page=m_global_page_pool.getPtr(ptr.p->m_pos[PRODUCER].m_current_pos.m_ptr_i);
  
  Uint32 total_free= ptr.p->m_free_buffer_words;
  assert(total_free >= sz);
  Uint32 pos= ptr.p->m_pos[PRODUCER].m_current_pos.m_idx;
  Uint32 free= File_formats::UNDO_PAGE_WORDS - pos;

  if(sz <= free)
  {
next:
    // fits this page wo/ problem
    ndbassert(total_free >= sz);
    ptr.p->m_free_buffer_words = total_free - sz;
    ptr.p->m_pos[PRODUCER].m_current_pos.m_idx = pos + sz;
    return ((File_formats::Undofile::Undo_page*)page)->m_data + pos;
  }
  
  /**
   * It didn't fit page...fill page with a NOOP log entry
   */
  Uint64 lsn= ptr.p->m_last_lsn - 1;
  File_formats::Undofile::Undo_page* undo= 
    (File_formats::Undofile::Undo_page*)page;
  undo->m_page_header.m_page_lsn_lo = lsn & 0xFFFFFFFF;
  undo->m_page_header.m_page_lsn_hi = lsn >> 32;
  undo->m_words_used= File_formats::UNDO_PAGE_WORDS - free;
  
  /**
   * Update free space with extra NOOP
   */
  ndbassert(ptr.p->m_free_file_words >= free);
  ptr.p->m_free_file_words -= free;

  validate_logfile_group(ptr, "get_log_buffer");
  
  pos= 0;
  assert(total_free >= free);
  total_free -= free;
  page= m_global_page_pool.getPtr(next_page(ptr.p, PRODUCER));
  goto next;
}

Uint32 
Lgman::next_page(Logfile_group* ptrP, Uint32 i)
{
  Uint32 page_ptr_i= ptrP->m_pos[i].m_current_pos.m_ptr_i;
  Uint32 left_in_range= ptrP->m_pos[i].m_current_page.m_idx;
  if(left_in_range > 0)
  {
    ptrP->m_pos[i].m_current_page.m_idx = left_in_range - 1;
    ptrP->m_pos[i].m_current_pos.m_ptr_i = page_ptr_i + 1;
    return page_ptr_i + 1;
  }
  else
  {
    Lgman::Page_map map(m_data_buffer_pool, ptrP->m_buffer_pages);
    Uint32 pos= (ptrP->m_pos[i].m_current_page.m_ptr_i + 2) % map.getSize();
    Lgman::Page_map::Iterator it;
    map.position(it, pos);

    union {
      Uint32 tmp[2];
      Lgman::Buffer_idx range;
    };
    
    tmp[0] = *it.data; map.next(it);
    tmp[1] = *it.data;
    
    ptrP->m_pos[i].m_current_page.m_ptr_i = pos;           // New index in map
    ptrP->m_pos[i].m_current_page.m_idx = range.m_idx - 1; // Free pages 
    ptrP->m_pos[i].m_current_pos.m_ptr_i = range.m_ptr_i;  // Current page
    // No need to set ptrP->m_current_pos.m_idx, that is set "in higher"-func
    return range.m_ptr_i;
  }
}

int
Logfile_client::get_log_buffer(Signal* signal, Uint32 sz, 
			       SimulatedBlock::Callback* callback)
{
  sz += 2; // lsn
  Lgman::Logfile_group key;
  key.m_logfile_group_id= m_logfile_group_id;
  Ptr<Lgman::Logfile_group> ptr;
  if(m_lgman->m_logfile_group_hash.find(ptr, key))
  {
    if(ptr.p->m_free_buffer_words >= (sz + 2*File_formats::UNDO_PAGE_WORDS)&& 
       ptr.p->m_log_buffer_waiters.isEmpty())
    {
      return 1;
    }
    
    bool empty= false;
    {
      Ptr<Lgman::Log_waiter> wait;
      LocalDLFifoList<Lgman::Log_waiter> 
	list(m_lgman->m_log_waiter_pool, ptr.p->m_log_buffer_waiters);
      
      empty= list.isEmpty();
      if(!list.seize(wait))
	return -1;
      
      wait.p->m_size= sz;
      wait.p->m_block= m_block;
      memcpy(&wait.p->m_callback, callback,sizeof(SimulatedBlock::Callback));
    }
	
    if(empty)
    { // Start ContinueB
      m_lgman->process_log_buffer_waiters(signal, ptr);
    }
    return 0;
  }
  return -1;
}

NdbOut&
operator<<(NdbOut& out, const Lgman::Buffer_idx& pos)
{
  out << "[ " 
      << pos.m_ptr_i << " "
      << pos.m_idx << " ]";
  return out;
}

NdbOut&
operator<<(NdbOut& out, const Lgman::Logfile_group::Position& pos)
{
  out << "[ (" 
      << pos.m_current_page.m_ptr_i << " "
      << pos.m_current_page.m_idx << ") ("
      << pos.m_current_pos.m_ptr_i << " "
      << pos.m_current_pos.m_idx << ") ]";
  return out;
}

void
Lgman::flush_log(Signal* signal, Ptr<Logfile_group> ptr)
{
  Logfile_group::Position consumer= ptr.p->m_pos[CONSUMER];
  Logfile_group::Position producer= ptr.p->m_pos[PRODUCER];
 
  jamEntry();

  if(consumer.m_current_page == producer.m_current_page)
  {
#if 0
    ndbout_c("ptr.p->m_file_pos[HEAD].m_ptr_i= %x", 
	     ptr.p->m_file_pos[HEAD].m_ptr_i);
    ndbout_c("consumer.m_current_page: %d %d producer.m_current_page: %d %d",
	     consumer.m_current_page.m_ptr_i, consumer.m_current_page.m_idx,
	     producer.m_current_page.m_ptr_i, producer.m_current_page.m_idx);
#endif
    if (! (ptr.p->m_state & Logfile_group::LG_DROPPING))
    {
      jam();
      signal->theData[0] = LgmanContinueB::FLUSH_LOG;
      signal->theData[1] = ptr.i;
      sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 2);
    }
    else
    {
      jam();
      ptr.p->m_state &= ~(Uint32)Logfile_group::LG_FLUSH_THREAD;
    }
    return;
  }
  
  bool full= false;
  Uint32 tot= 0;
  while(!(consumer.m_current_page == producer.m_current_page) && !full)
  {
    validate_logfile_group(ptr, "before flush log");

    Uint32 cnt; // pages written
    Uint32 page= consumer.m_current_pos.m_ptr_i;
    if(consumer.m_current_page.m_ptr_i == producer.m_current_page.m_ptr_i)
    {
      if(consumer.m_current_page.m_idx > producer.m_current_page.m_idx)
      {
	jam();
	Uint32 tmp= 
	  consumer.m_current_page.m_idx - producer.m_current_page.m_idx;
	cnt= write_log_pages(signal, ptr, page, tmp);
	assert(cnt <= tmp);
	
	consumer.m_current_pos.m_ptr_i += cnt;
	consumer.m_current_page.m_idx -= cnt;
	full= (tmp > cnt);
      }
      else
      {
	// Only 1 chunk
	ndbassert(ptr.p->m_buffer_pages.getSize() == 2); 
	Uint32 tmp= consumer.m_current_page.m_idx + 1;
	cnt= write_log_pages(signal, ptr, page, tmp);
	assert(cnt <= tmp);

	if(cnt == tmp)
	{
	  jam();
	  /**
	   * Entire chunk is written
	   *   move to next
	   */
	  ptr.p->m_pos[CONSUMER].m_current_page.m_idx= 0;
	  next_page(ptr.p, CONSUMER);
	  consumer = ptr.p->m_pos[CONSUMER];
 	}
	else
	{
	  jam();
	  /**
	   * Failed to write entire chunk...
	   */
	  full= true;
	  consumer.m_current_page.m_idx -= cnt;
	  consumer.m_current_pos.m_ptr_i += cnt;
	}
      }
    }
    else
    {
      Uint32 tmp= consumer.m_current_page.m_idx + 1;
      cnt= write_log_pages(signal, ptr, page, tmp);
      assert(cnt <= tmp);

      if(cnt == tmp)
      {
	jam();
	/**
	 * Entire chunk is written
	 *   move to next
	 */
	ptr.p->m_pos[CONSUMER].m_current_page.m_idx= 0;
	next_page(ptr.p, CONSUMER);
	consumer = ptr.p->m_pos[CONSUMER];
      }
      else
      {
	jam();
	/**
	 * Failed to write entire chunk...
	 */
	full= true;
	consumer.m_current_page.m_idx -= cnt;
	consumer.m_current_pos.m_ptr_i += cnt;
      }
    }

    tot += cnt;
    if(cnt)
      validate_logfile_group(ptr, " after flush_log");
  }

  ptr.p->m_pos[CONSUMER]= consumer;
  
  if (! (ptr.p->m_state & Logfile_group::LG_DROPPING))
  {
    signal->theData[0] = LgmanContinueB::FLUSH_LOG;
    signal->theData[1] = ptr.i;
    sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
  }
  else
  {
    ptr.p->m_state &= ~(Uint32)Logfile_group::LG_FLUSH_THREAD;
  }
  
  if(tot > 0 && !ptr.p->m_log_buffer_waiters.isEmpty() &&
     !(ptr.p->m_state & Logfile_group::LG_WAITERS_THREAD))
  {
    jam();
    process_log_buffer_waiters(signal, ptr);
  }
}

void
Lgman::process_log_buffer_waiters(Signal* signal, Ptr<Logfile_group> ptr)
{
  Uint32 free_buffer= ptr.p->m_free_buffer_words;
  LocalDLFifoList<Log_waiter> 
    list(m_log_waiter_pool, ptr.p->m_log_buffer_waiters);

  if(list.isEmpty())
  {
    ptr.p->m_state &= (Uint32)Logfile_group::LG_WAITERS_THREAD;
    return;
  }
  
  bool removed= false;
  Ptr<Log_waiter> waiter;
  list.first(waiter);
  if(waiter.p->m_size + 2*File_formats::UNDO_PAGE_WORDS < free_buffer)
  {
    removed= true;
    Uint32 block = waiter.p->m_block;
    SimulatedBlock* b = globalData.getBlock(block);
    b->execute(signal, waiter.p->m_callback, 0);

    list.release(waiter);
  }
  
  if(removed && !list.isEmpty())
  {
    ptr.p->m_state |= Logfile_group::LG_WAITERS_THREAD;
    signal->theData[0] = LgmanContinueB::PROCESS_LOG_BUFFER_WAITERS;
    signal->theData[1] = ptr.i;
    sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
  }
  else
  {
    ptr.p->m_state &= (Uint32)Logfile_group::LG_WAITERS_THREAD;
  }
}

Uint32
Lgman::write_log_pages(Signal* signal, Ptr<Logfile_group> ptr,
		       Uint32 pageId, Uint32 in_pages)
{
  assert(in_pages);
  Ptr<Undofile> filePtr;
  Buffer_idx head= ptr.p->m_file_pos[HEAD];
  Buffer_idx tail= ptr.p->m_file_pos[TAIL];
  m_file_pool.getPtr(filePtr, head.m_ptr_i);
  
  if(filePtr.p->m_online.m_outstanding > 0)
  {
    jam();
    return 0;
  }
  
  Uint32 sz= filePtr.p->m_file_size - 1; // skip zero
  Uint32 max, pages= in_pages;

  if(!(head.m_ptr_i == tail.m_ptr_i && head.m_idx < tail.m_idx))
  {
    max= sz - head.m_idx;
  }
  else
  {
    max= tail.m_idx - head.m_idx;
  }

  FsReadWriteReq* req= (FsReadWriteReq*)signal->getDataPtrSend();
  req->filePointer = filePtr.p->m_fd;
  req->userReference = reference();
  req->userPointer = filePtr.i;
  req->varIndex = 1+head.m_idx; // skip zero page
  req->numberOfPages = pages;
  req->data.pageData[0] = pageId;
  req->operationFlag = 0;
  FsReadWriteReq::setFormatFlag(req->operationFlag, 
				FsReadWriteReq::fsFormatGlobalPage);

  if(max > pages)
  {
    jam();
    max= pages;
    head.m_idx += max;
    ptr.p->m_file_pos[HEAD] = head;  
    
    sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 
	       FsReadWriteReq::FixedLength + 1, JBA);

    ptr.p->m_outstanding_fs++;
    filePtr.p->m_online.m_outstanding = max;
    filePtr.p->m_state |= Undofile::FS_OUTSTANDING;

    File_formats::Undofile::Undo_page *page= (File_formats::Undofile::Undo_page*)
      m_global_page_pool.getPtr(pageId + max - 1);
    Uint64 lsn = 0;
    lsn += page->m_page_header.m_page_lsn_hi; lsn <<= 32;
    lsn += page->m_page_header.m_page_lsn_lo;
    
    filePtr.p->m_online.m_lsn = lsn;  // Store last writereq lsn on file
    ptr.p->m_last_sync_req_lsn = lsn; // And logfile_group
  }
  else
  {
    jam();
    req->numberOfPages = max;
    FsReadWriteReq::setSyncFlag(req->operationFlag, 1);
    
    sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 
	       FsReadWriteReq::FixedLength + 1, JBA);

    ptr.p->m_outstanding_fs++;
    filePtr.p->m_online.m_outstanding = max;
    filePtr.p->m_state |= Undofile::FS_OUTSTANDING;

    File_formats::Undofile::Undo_page *page= (File_formats::Undofile::Undo_page*)
      m_global_page_pool.getPtr(pageId + max - 1);
    Uint64 lsn = 0;
    lsn += page->m_page_header.m_page_lsn_hi; lsn <<= 32;
    lsn += page->m_page_header.m_page_lsn_lo;
    
    filePtr.p->m_online.m_lsn = lsn;  // Store last writereq lsn on file
    ptr.p->m_last_sync_req_lsn = lsn; // And logfile_group
    
    Ptr<Undofile> next = filePtr;
    LocalDLFifoList<Undofile> files(m_file_pool, ptr.p->m_files);
    if(!files.next(next))
    {
      jam();
      files.first(next);
    }
    ndbout_c("changing file from %d to %d", filePtr.i, next.i);
    ndbassert(filePtr.i != next.i);
    filePtr.p->m_state |= Undofile::FS_MOVE_NEXT;
    next.p->m_state &= ~(Uint32)Undofile::FS_EMPTY;

    head.m_idx= 0;
    head.m_ptr_i= next.i;
    ptr.p->m_file_pos[HEAD] = head;
    if(max < pages)
      max += write_log_pages(signal, ptr, pageId + max, pages - max);
  }
  
  assert(max);
  return max;
}

void
Lgman::execFSWRITEREF(Signal* signal)
{
  jamEntry();
  SimulatedBlock::execFSWRITEREF(signal);
  ndbrequire(false);
}

void
Lgman::execFSWRITECONF(Signal* signal)
{
  jamEntry();
  FsConf * conf = (FsConf*)signal->getDataPtr();
  Ptr<Undofile> ptr;
  m_file_pool.getPtr(ptr, conf->userPointer);

  ndbassert(ptr.p->m_state & Undofile::FS_OUTSTANDING);
  ptr.p->m_state &= ~(Uint32)Undofile::FS_OUTSTANDING;

  Ptr<Logfile_group> lg_ptr;
  m_logfile_group_pool.getPtr(lg_ptr, ptr.p->m_logfile_group_ptr_i);
  
  Uint32 cnt= lg_ptr.p->m_outstanding_fs;
  ndbassert(cnt);
  
  if(lg_ptr.p->m_next_reply_ptr_i == ptr.i)
  {
    Uint32 tot= 0;
    Uint64 lsn = 0;
    LocalDLFifoList<Undofile> files(m_file_pool, lg_ptr.p->m_files);
    while(cnt && ! (ptr.p->m_state & Undofile::FS_OUTSTANDING))
    {
      Uint32 state= ptr.p->m_state;
      Uint32 pages= ptr.p->m_online.m_outstanding;
      ndbassert(pages);
      ptr.p->m_online.m_outstanding= 0;
      ptr.p->m_state &= ~(Uint32)Undofile::FS_MOVE_NEXT;
      tot += pages;
      cnt--;
      
      lsn = ptr.p->m_online.m_lsn;

      if((state & Undofile::FS_MOVE_NEXT) && !files.next(ptr))
	files.first(ptr);
    }
    
    lg_ptr.p->m_outstanding_fs = cnt;
    lg_ptr.p->m_free_buffer_words += (tot * File_formats::UNDO_PAGE_WORDS);
    lg_ptr.p->m_next_reply_ptr_i = ptr.i;
    lg_ptr.p->m_last_synced_lsn = lsn;

    if(! (lg_ptr.p->m_state & Logfile_group::LG_SYNC_WAITERS_THREAD))
    {
      process_log_sync_waiters(signal, lg_ptr);
    }
  }
  
  return;
}

void
Lgman::execLCP_FRAG_ORD(Signal* signal)
{
  jamEntry();

  LcpFragOrd * ord = (LcpFragOrd *)signal->getDataPtr();
  Uint32 lcp_id= ord->lcpId;
  Uint32 frag_id = ord->fragmentId;
  Uint32 table_id = ord->tableId;

  Ptr<Logfile_group> ptr;
  m_logfile_group_list.first(ptr);
  
  Uint32 entry= lcp_id == m_latest_lcp ? 
    File_formats::Undofile::UNDO_LCP : File_formats::Undofile::UNDO_LCP_FIRST;
  if(!ptr.isNull() && ! (ptr.p->m_state & Logfile_group::LG_CUT_LOG_THREAD))
  {
    jam();
    ptr.p->m_state |= Logfile_group::LG_CUT_LOG_THREAD;
    signal->theData[0] = LgmanContinueB::CUT_LOG_TAIL;
    signal->theData[1] = ptr.i;
    sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
  }
  
  if(!ptr.isNull())
  {
    Uint32 undo[3];
    undo[0] = lcp_id;
    undo[1] = (table_id << 16) | frag_id;
    undo[2] = (entry << 16 ) | (sizeof(undo) >> 2);

    Uint64 last_lsn= m_last_lsn;
    
    if(ptr.p->m_last_lsn == last_lsn
#ifdef VM_TRACE
       && ((rand() % 100) > 50)
#endif
       )
    {
      undo[2] |= File_formats::Undofile::UNDO_NEXT_LSN << 16;
      Uint32 *dst= get_log_buffer(ptr, sizeof(undo) >> 2);
      memcpy(dst, undo, sizeof(undo));
      ndbassert(ptr.p->m_free_file_words >= (sizeof(undo) >> 2));
      ptr.p->m_free_file_words -= (sizeof(undo) >> 2);
    }
    else
    {
      Uint32 *dst= get_log_buffer(ptr, (sizeof(undo) >> 2) + 2);      
      * dst++ = last_lsn >> 32;
      * dst++ = last_lsn & 0xFFFFFFFF;
      memcpy(dst, undo, sizeof(undo));
      ndbassert(ptr.p->m_free_file_words >= (sizeof(undo) >> 2));
      ptr.p->m_free_file_words -= ((sizeof(undo) >> 2) + 2);
    }
    ptr.p->m_last_lcp_lsn = last_lsn;
    m_last_lsn = ptr.p->m_last_lsn = last_lsn + 1;

    validate_logfile_group(ptr, "execLCP_FRAG_ORD");
  }
  
  while(!ptr.isNull())
  {
    /**
     * First LCP_FRAGORD for each LCP, sets tail pos
     */
    if(m_latest_lcp != lcp_id)
    {
      ptr.p->m_tail_pos[0] = ptr.p->m_tail_pos[1];
      ptr.p->m_tail_pos[1] = ptr.p->m_tail_pos[2];
      ptr.p->m_tail_pos[2] = ptr.p->m_file_pos[HEAD];
    }
    
    if(0)
      ndbout_c
	("execLCP_FRAG_ORD (%d %d) (%d %d) (%d %d) free pages: %d", 
	 ptr.p->m_tail_pos[0].m_ptr_i, ptr.p->m_tail_pos[0].m_idx,
	 ptr.p->m_tail_pos[1].m_ptr_i, ptr.p->m_tail_pos[1].m_idx,
	 ptr.p->m_tail_pos[2].m_ptr_i, ptr.p->m_tail_pos[2].m_idx,
	 (ptr.p->m_free_file_words / File_formats::UNDO_PAGE_WORDS));
    
    m_logfile_group_list.next(ptr);
  }
  
  m_latest_lcp = lcp_id;
}

void
Lgman::execEND_LCP_REQ(Signal* signal)
{
  EndLcpReq* req= (EndLcpReq*)signal->getDataPtr();
  ndbrequire(m_latest_lcp == req->backupId);

  Ptr<Logfile_group> ptr;
  m_logfile_group_list.first(ptr);
  bool wait= false;
  while(!ptr.isNull())
  {
    Uint64 lcp_lsn = ptr.p->m_last_lcp_lsn;
    if(ptr.p->m_last_synced_lsn < lcp_lsn)
    {
      wait= true;
      if(signal->getSendersBlockRef() != reference())
      {
	Logfile_client tmp(this, this, ptr.p->m_logfile_group_id);
	Logfile_client::Request req;
	req.m_callback.m_callbackData = ptr.i;
	req.m_callback.m_callbackFunction = safe_cast(&Lgman::endlcp_callback);
	ndbrequire(tmp.sync_lsn(signal, lcp_lsn, &req, 0) == 0);
      }
    }
    else
    {
      ptr.p->m_last_lcp_lsn = 0;
    }
    m_logfile_group_list.next(ptr);
  }
  
  if(wait)
  {
    return;
  }

  signal->theData[0] = 0;
  sendSignal(DBLQH_REF, GSN_END_LCP_CONF, signal, 1, JBB);
}

void
Lgman::endlcp_callback(Signal* signal, Uint32 ptr, Uint32 res)
{
  EndLcpReq* req= (EndLcpReq*)signal->getDataPtr();
  req->backupId = m_latest_lcp;
  execEND_LCP_REQ(signal);
}

void
Lgman::cut_log_tail(Signal* signal, Ptr<Logfile_group> ptr)
{
  Buffer_idx tmp= ptr.p->m_tail_pos[0];
  Buffer_idx tail= ptr.p->m_file_pos[TAIL];

  Ptr<Undofile> filePtr;
  m_file_pool.getPtr(filePtr, tail.m_ptr_i);
  
  bool done= true;
  if(!(tmp == tail))
  {
    Uint32 free;
    if(tmp.m_ptr_i == tail.m_ptr_i && tail.m_idx < tmp.m_idx)
    {
      free= tmp.m_idx - tail.m_idx; 
      ptr.p->m_free_file_words += free * File_formats::UNDO_PAGE_WORDS;
      ptr.p->m_file_pos[TAIL] = tmp;
    }
    else
    {
      free= filePtr.p->m_file_size - tail.m_idx - 1;
      ptr.p->m_free_file_words += free * File_formats::UNDO_PAGE_WORDS;
      
      Ptr<Undofile> next = filePtr;
      LocalDLFifoList<Undofile> files(m_file_pool, ptr.p->m_files);
      while(files.next(next) && (next.p->m_state & Undofile::FS_EMPTY))
	ndbassert(next.i != filePtr.i);
      if(next.isNull())
      {
	jam();
	files.first(next);
	while((next.p->m_state & Undofile::FS_EMPTY) && files.next(next))
	  ndbassert(next.i != filePtr.i);
      }
      
      tmp.m_idx= 0;
      tmp.m_ptr_i= next.i;
      ptr.p->m_file_pos[TAIL] = tmp;
      done= false;      
    }
  } 

  validate_logfile_group(ptr, "cut log");
  
  if (done)
  {
    ptr.p->m_state &= ~(Uint32)Logfile_group::LG_CUT_LOG_THREAD;
    m_logfile_group_list.next(ptr); 
  }
  
  if(!done || !ptr.isNull())
  {
    ptr.p->m_state |= Logfile_group::LG_CUT_LOG_THREAD;
    signal->theData[0] = LgmanContinueB::CUT_LOG_TAIL;
    signal->theData[1] = ptr.i;
    sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
  }
}

void
Lgman::execSUB_GCP_COMPLETE_REP(Signal* signal)
{
  jamEntry();
  Uint32 gci= ((SubGcpCompleteRep*)signal->getDataPtr())->gci;
  
  Ptr<Logfile_group> ptr;
  m_logfile_group_list.first(ptr);

  /**
   * Filter all logfile groups in parallell
   */
  return; // NOT IMPLETMENT YET
  
  signal->theData[0] = LgmanContinueB::FILTER_LOG;
  while(!ptr.isNull())
  {
    signal->theData[1] = ptr.i;
    sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
    m_logfile_group_list.next(ptr);
  }
}

int
Lgman::alloc_log_space(Uint32 ref, Uint32 words)
{
  ndbassert(words);
  words += 2; // lsn
  Logfile_group key;
  key.m_logfile_group_id= ref;
  Ptr<Logfile_group> ptr;
  if(m_logfile_group_hash.find(ptr, key) && 
     ptr.p->m_free_file_words >= (words + (4 * File_formats::UNDO_PAGE_WORDS)))
  {
    ptr.p->m_free_file_words -= words;
    validate_logfile_group(ptr, "alloc_log_space");
    return 0;
  }
  
  if(ptr.isNull())
  {
    return -1;
  }
  
  return 1501;
}

int
Lgman::free_log_space(Uint32 ref, Uint32 words)
{
  ndbassert(words);
  Logfile_group key;
  key.m_logfile_group_id= ref;
  Ptr<Logfile_group> ptr;
  if(m_logfile_group_hash.find(ptr, key))
  {
    ptr.p->m_free_file_words += (words + 2);
    validate_logfile_group(ptr, "free_log_space");
    return 0;
  }
  ndbassert(false);
  return -1;
}

template<Uint32 cnt>
Uint64
Logfile_client::add_entry(const Change* src)
{
  Uint32 i, tot= 0;
  for(i= 0; i<cnt; i++)
  {
    tot += src[i].len;
  }
  
  Uint32 *dst;
  Uint64 last_lsn= m_lgman->m_last_lsn;
  {
    Lgman::Logfile_group key;
    key.m_logfile_group_id= m_logfile_group_id;
    Ptr<Lgman::Logfile_group> ptr;
    if(m_lgman->m_logfile_group_hash.find(ptr, key))
    {
      Uint64 last_lsn_filegroup= ptr.p->m_last_lsn;
      if(last_lsn_filegroup == last_lsn
#ifdef VM_TRACE
	 && ((rand() % 100) > 50)
#endif
	 )
      {
	dst= m_lgman->get_log_buffer(ptr, tot);
	for(i= 0; i<cnt; i++)
	{
	  memcpy(dst, src[i].ptr, 4*src[i].len);
	  dst += src[i].len;
	}
	* (dst - 1) |= File_formats::Undofile::UNDO_NEXT_LSN << 16;
	ptr.p->m_free_file_words += 2;
	ptr.p->m_free_buffer_words += 2;
	m_lgman->validate_logfile_group(ptr);
      }
      else
      {
	dst= m_lgman->get_log_buffer(ptr, tot + 2);
	* dst++ = last_lsn >> 32;
	* dst++ = last_lsn & 0xFFFFFFFF;
	for(i= 0; i<cnt; i++)
	{
	  memcpy(dst, src[i].ptr, 4*src[i].len);
	  dst += src[i].len;
	}
      }
    }
    
    m_lgman->m_last_lsn = ptr.p->m_last_lsn = last_lsn + 1;
    
    return last_lsn;
  }
}

template Uint64 Logfile_client::add_entry<1>(const Change*);
template Uint64 Logfile_client::add_entry<3>(const Change*);

void
Lgman::execSTART_RECREQ(Signal* signal)
{
  m_latest_lcp = signal->theData[0];
  
  Ptr<Logfile_group> ptr;
  m_logfile_group_list.first(ptr);

  if(ptr.i != RNIL)
  {
    infoEvent("Applying undo to LCP: %d", m_latest_lcp);
    find_log_head(signal, ptr);
    return;
  }
  
  signal->theData[0] = reference();
  sendSignal(DBLQH_REF, GSN_START_RECCONF, signal, 1, JBB);
}

void
Lgman::find_log_head(Signal* signal, Ptr<Logfile_group> ptr)
{
  if(ptr.p->m_meta_files.isEmpty() && ptr.p->m_files.isEmpty())
  {
    jam();
    /**
     * Logfile_group wo/ any files 
     */
    
    m_logfile_group_list.next(ptr);
    signal->theData[0] = LgmanContinueB::FIND_LOG_HEAD;
    signal->theData[1] = ptr.i;
    sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
    return;
  }

  ptr.p->m_state = Logfile_group::LG_SORTING;
  
  /**
Thread
bk commit into 5.1 tree (jonas:1.1922)jonas10 Oct