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.1941 05/10/25 14:18:39 jonas@stripped +225 -0
ndb import of varsize/dd
with mysql part of DD removed
storage/ndb/src/kernel/vm/Rope.hpp
1.1 05/10/25 14:18:33 jonas@stripped +117 -0
New BitKeeper file ``storage/ndb/src/kernel/vm/Rope.hpp''
storage/ndb/src/kernel/vm/Rope.cpp
1.1 05/10/25 14:18:33 jonas@stripped +173 -0
New BitKeeper file ``storage/ndb/src/kernel/vm/Rope.cpp''
storage/ndb/src/kernel/vm/KeyTable2Ref.hpp
1.1 05/10/25 14:18:33 jonas@stripped +51 -0
New BitKeeper file ``storage/ndb/src/kernel/vm/KeyTable2Ref.hpp''
storage/ndb/src/kernel/vm/DLCHashTable.hpp
1.1 05/10/25 14:18:33 jonas@stripped +82 -0
New BitKeeper file ``storage/ndb/src/kernel/vm/DLCHashTable.hpp''
storage/ndb/src/kernel/vm/Rope.hpp
1.0 05/10/25 14:18:33 jonas@stripped +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/25 14:18:33 jonas@stripped +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/25 14:18:33 jonas@stripped +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/25 14:18:33 jonas@stripped +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/25 14:18:32 jonas@stripped +119 -0
New BitKeeper file ``storage/ndb/src/kernel/vm/DLCFifoList.hpp''
storage/ndb/src/kernel/blocks/tsman.hpp
1.1 05/10/25 14:18:32 jonas@stripped +372 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/tsman.hpp''
storage/ndb/src/kernel/blocks/tsman.cpp
1.1 05/10/25 14:18:32 jonas@stripped +2101 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/tsman.cpp''
storage/ndb/src/kernel/blocks/restore.hpp
1.1 05/10/25 14:18:32 jonas@stripped +154 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/restore.hpp''
storage/ndb/src/kernel/blocks/restore.cpp
1.1 05/10/25 14:18:32 jonas@stripped +1211 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/restore.cpp''
storage/ndb/src/kernel/blocks/print_file.cpp
1.1 05/10/25 14:18:32 jonas@stripped +370 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/print_file.cpp''
storage/ndb/src/kernel/vm/DLCFifoList.hpp
1.0 05/10/25 14:18:32 jonas@stripped +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/25 14:18:32 jonas@stripped +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/25 14:18:32 jonas@stripped +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/25 14:18:32 jonas@stripped +0 -0
BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/restore.hpp
storage/ndb/src/kernel/blocks/restore.cpp
1.0 05/10/25 14:18:32 jonas@stripped +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/25 14:18:32 jonas@stripped +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.1 05/10/25 14:18:31 jonas@stripped +659 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/pgman.hpp''
storage/ndb/src/kernel/blocks/pgman.cpp
1.1 05/10/25 14:18:31 jonas@stripped +2214 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/pgman.cpp''
storage/ndb/src/kernel/blocks/lgman.hpp
1.1 05/10/25 14:18:31 jonas@stripped +342 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/lgman.hpp''
storage/ndb/src/kernel/blocks/lgman.cpp
1.1 05/10/25 14:18:31 jonas@stripped +2952 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/lgman.cpp''
storage/ndb/src/kernel/blocks/diskpage.hpp
1.1 05/10/25 14:18:31 jonas@stripped +236 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/diskpage.hpp''
storage/ndb/src/kernel/blocks/pgman.hpp
1.0 05/10/25 14:18:31 jonas@stripped +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/25 14:18:31 jonas@stripped +0 -0
BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/pgman.cpp
storage/ndb/src/kernel/blocks/lgman.hpp
1.0 05/10/25 14:18:31 jonas@stripped +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/25 14:18:31 jonas@stripped +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/25 14:18:31 jonas@stripped +0 -0
BitKeeper file /home/jonas/src/51-clean/storage/ndb/src/kernel/blocks/diskpage.hpp
storage/ndb/src/kernel/blocks/diskpage.cpp
1.1 05/10/25 14:18:30 jonas@stripped +75 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/diskpage.cpp''
storage/ndb/src/kernel/blocks/dbtup/tuppage.hpp
1.1 05/10/25 14:18:30 jonas@stripped +231 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/dbtup/tuppage.hpp''
storage/ndb/src/kernel/blocks/dbtup/tuppage.cpp
1.1 05/10/25 14:18:30 jonas@stripped +330 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/dbtup/tuppage.cpp''
storage/ndb/src/kernel/blocks/dbtup/test_varpage.cpp
1.1 05/10/25 14:18:30 jonas@stripped +125 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/dbtup/test_varpage.cpp''
storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.hpp
1.1 05/10/25 14:18:30 jonas@stripped +57 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.hpp''
storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.cpp
1.1 05/10/25 14:18:30 jonas@stripped +120 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.cpp''
storage/ndb/src/kernel/blocks/diskpage.cpp
1.0 05/10/25 14:18:30 jonas@stripped +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/25 14:18:30 jonas@stripped +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.0 05/10/25 14:18:30 jonas@stripped +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/25 14:18:30 jonas@stripped +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/25 14:18:30 jonas@stripped +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/25 14:18:30 jonas@stripped +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/25 14:18:29 jonas@stripped +846 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/dbtup/DbtupVarAlloc.cpp''
storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp
1.1 05/10/25 14:18:29 jonas@stripped +1511 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp''
storage/ndb/src/kernel/blocks/dbdih/printSysfile.cpp
1.1 05/10/25 14:18:29 jonas@stripped +160 -0
New BitKeeper file ``storage/ndb/src/kernel/blocks/dbdih/printSysfile.cpp''
storage/ndb/include/kernel/signaldata/TsmanContinueB.hpp
1.1 05/10/25 14:18:29 jonas@stripped +37 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/TsmanContinueB.hpp''
storage/ndb/include/kernel/signaldata/RestoreImpl.hpp
1.1 05/10/25 14:18:29 jonas@stripped +66 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/RestoreImpl.hpp''
storage/ndb/include/kernel/signaldata/RestoreContinueB.hpp
1.1 05/10/25 14:18:29 jonas@stripped +38 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/RestoreContinueB.hpp''
storage/ndb/src/kernel/blocks/dbtup/DbtupVarAlloc.cpp
1.0 05/10/25 14:18:29 jonas@stripped +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/25 14:18:29 jonas@stripped +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/25 14:18:29 jonas@stripped +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/25 14:18:29 jonas@stripped +0 -0
BitKeeper file
/home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/TsmanContinueB.hpp
storage/ndb/include/kernel/signaldata/RestoreImpl.hpp
1.0 05/10/25 14:18:29 jonas@stripped +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/25 14:18:29 jonas@stripped +0 -0
BitKeeper file
/home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/RestoreContinueB.hpp
storage/ndb/include/kernel/signaldata/PgmanContinueB.hpp
1.1 05/10/25 14:18:28 jonas@stripped +36 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/PgmanContinueB.hpp''
storage/ndb/include/kernel/signaldata/LgmanContinueB.hpp
1.1 05/10/25 14:18:28 jonas@stripped +39 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/LgmanContinueB.hpp''
storage/ndb/include/kernel/signaldata/Extent.hpp
1.1 05/10/25 14:18:28 jonas@stripped +119 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/Extent.hpp''
storage/ndb/include/kernel/signaldata/DropObj.hpp
1.1 05/10/25 14:18:28 jonas@stripped +118 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/DropObj.hpp''
storage/ndb/include/kernel/signaldata/DropFilegroupImpl.hpp
1.1 05/10/25 14:18:28 jonas@stripped +171 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/DropFilegroupImpl.hpp''
storage/ndb/include/kernel/signaldata/PgmanContinueB.hpp
1.0 05/10/25 14:18:28 jonas@stripped +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/25 14:18:28 jonas@stripped +0 -0
BitKeeper file
/home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/LgmanContinueB.hpp
storage/ndb/include/kernel/signaldata/Extent.hpp
1.0 05/10/25 14:18:28 jonas@stripped +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/25 14:18:28 jonas@stripped +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/25 14:18:28 jonas@stripped +0 -0
BitKeeper file
/home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/DropFilegroupImpl.hpp
storage/ndb/include/kernel/signaldata/DropFilegroup.hpp
1.1 05/10/25 14:18:27 jonas@stripped +191 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/DropFilegroup.hpp''
storage/ndb/include/kernel/signaldata/DictObjOp.hpp
1.1 05/10/25 14:18:27 jonas@stripped +104 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/DictObjOp.hpp''
storage/ndb/include/kernel/signaldata/CreateObj.hpp
1.1 05/10/25 14:18:27 jonas@stripped +107 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/CreateObj.hpp''
storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp
1.1 05/10/25 14:18:27 jonas@stripped +193 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp''
storage/ndb/include/kernel/signaldata/CreateFilegroup.hpp
1.1 05/10/25 14:18:27 jonas@stripped +198 -0
New BitKeeper file ``storage/ndb/include/kernel/signaldata/CreateFilegroup.hpp''
storage/ndb/include/kernel/signaldata/DropFilegroup.hpp
1.0 05/10/25 14:18:27 jonas@stripped +0 -0
BitKeeper file
/home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/DropFilegroup.hpp
storage/ndb/include/kernel/signaldata/DictObjOp.hpp
1.0 05/10/25 14:18:27 jonas@stripped +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/25 14:18:27 jonas@stripped +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/25 14:18:27 jonas@stripped +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/25 14:18:27 jonas@stripped +0 -0
BitKeeper file
/home/jonas/src/51-clean/storage/ndb/include/kernel/signaldata/CreateFilegroup.hpp
sql/ha_ndbcluster.cc
1.221 05/10/25 14:18:27 jonas@stripped +12 -2
#ifdef ndb disk parts
mysql-test/t/disabled.def
1.10 05/10/25 14:18:27 jonas@stripped +2 -0
disable federated
storage/ndb/tools/select_all.cpp
1.24 05/10/13 10:52:15 jonas@stripped[jonas] +47 -13
Import ndb varsize/dd except mysql disk part
storage/ndb/tools/restore/consumer_restore.cpp
1.21 05/10/13 10:52:15 jonas@stripped[jonas] +3 -3
Import ndb varsize/dd except mysql disk part
storage/ndb/tools/restore/Restore.cpp
1.30 05/10/13 10:52:15 jonas@stripped[jonas] +41 -19
Import ndb varsize/dd except mysql disk part
storage/ndb/tools/listTables.cpp
1.24 05/10/13 10:52:15 jonas@stripped[jonas] +13 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/tools/desc.cpp
1.21 05/10/13 10:52:15 jonas@stripped[jonas] +171 -39
Import ndb varsize/dd except mysql disk part
storage/ndb/test/tools/hugoScanUpdate.cpp
1.10 05/10/13 10:52:15 jonas@stripped[jonas] +9 -7
Import ndb varsize/dd except mysql disk part
storage/ndb/test/tools/hugoPkReadRecord.cpp
1.9 05/10/13 10:52:15 jonas@stripped[jonas] +1 -54
Import ndb varsize/dd except mysql disk part
storage/ndb/test/tools/hugoLoad.cpp
1.7 05/10/13 10:52:15 jonas@stripped[jonas] +30 -14
Import ndb varsize/dd except mysql disk part
storage/ndb/test/src/UtilTransactions.cpp
1.23 05/10/13 10:52:15 jonas@stripped[jonas] +6 -9
Import ndb varsize/dd except mysql disk part
storage/ndb/test/src/NDBT_Test.cpp
1.29 05/10/13 10:52:15 jonas@stripped[jonas] +131 -12
Import ndb varsize/dd except mysql disk part
storage/ndb/test/src/NDBT_Tables.cpp
1.17 05/10/13 10:52:15 jonas@stripped[jonas] +153 -10
Import ndb varsize/dd except mysql disk part
storage/ndb/test/src/NDBT_ResultRow.cpp
1.16 05/10/17 06:59:48 jonas@stripped[jonas] +11 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/test/src/HugoTransactions.cpp
1.28 05/10/13 10:52:15 jonas@stripped[jonas] +3 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/test/src/HugoOperations.cpp
1.27 05/10/13 10:52:15 jonas@stripped[jonas] +7 -4
Import ndb varsize/dd except mysql disk part
storage/ndb/test/src/HugoCalculator.cpp
1.21 05/10/13 10:52:15 jonas@stripped[jonas] +41 -14
Import ndb varsize/dd except mysql disk part
storage/ndb/test/run-test/daily-basic-tests.txt
1.35 05/10/13 10:52:15 jonas@stripped[jonas] +90 -74
Import ndb varsize/dd except mysql disk part
storage/ndb/test/ndbapi/testPartitioning.cpp
1.9 05/10/13 10:52:15 jonas@stripped[jonas] +14 -5
Import ndb varsize/dd except mysql disk part
storage/ndb/test/ndbapi/testOIBasic.cpp
1.45 05/10/13 10:52:15 jonas@stripped[jonas] +15 -7
Import ndb varsize/dd except mysql disk part
storage/ndb/test/ndbapi/testLcp.cpp
1.7 05/10/13 10:52:15 jonas@stripped[jonas] +316 -104
Import ndb varsize/dd except mysql disk part
storage/ndb/test/ndbapi/testDict.cpp
1.25 05/10/13 10:52:15 jonas@stripped[jonas] +102 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/test/ndbapi/flexBench.cpp
1.13 05/10/13 10:52:15 jonas@stripped[jonas] +4 -4
Import ndb varsize/dd except mysql disk part
storage/ndb/test/ndbapi/create_tab.cpp
1.10 05/10/13 10:52:15 jonas@stripped[jonas] +33 -8
Import ndb varsize/dd except mysql disk part
storage/ndb/test/include/NdbSchemaOp.hpp
1.14 05/10/13 10:52:15 jonas@stripped[jonas] +3 -3
Import ndb varsize/dd except mysql disk part
storage/ndb/test/include/NdbRestarter.hpp
1.6 05/10/13 10:52:15 jonas@stripped[jonas] +2 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/test/include/NDBT_Test.hpp
1.17 05/10/13 10:52:15 jonas@stripped[jonas] +9 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/test/include/NDBT_Tables.hpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +4 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/test/include/NDBT_Table.hpp
1.12 05/10/13 10:52:15 jonas@stripped[jonas] +3 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/test/include/HugoTransactions.hpp
1.11 05/10/13 10:52:15 jonas@stripped[jonas] +2 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/test/include/HugoCalculator.hpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +2 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/ndberror.c
1.44 05/10/25 10:09:00 jonas@stripped[jonas] +25 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/TransporterFacade.cpp
1.46 05/10/13 10:52:15 jonas@stripped[jonas] +3 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/Ndbif.cpp
1.34 05/10/13 10:52:15 jonas@stripped[jonas] +9 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbScanOperation.cpp
1.73 05/10/13 10:52:15 jonas@stripped[jonas] +25 -22
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbReceiver.cpp
1.17 05/10/13 10:52:15 jonas@stripped[jonas] +12 -12
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbRecAttr.cpp
1.24 05/10/13 10:52:15 jonas@stripped[jonas] +205 -208
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbOperationSearch.cpp
1.28 05/10/13 10:52:15 jonas@stripped[jonas] +101 -45
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbOperationInt.cpp
1.17 05/10/25 10:09:00 jonas@stripped[jonas] +13 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbOperationExec.cpp
1.21 05/10/13 10:52:15 jonas@stripped[jonas] +3 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbOperationDefine.cpp
1.23 05/10/13 10:52:15 jonas@stripped[jonas] +32 -39
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbOperation.cpp
1.17 05/10/13 10:52:15 jonas@stripped[jonas] +9 -16
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbIndexOperation.cpp
1.26 05/10/13 10:52:15 jonas@stripped[jonas] +1 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp
1.21 05/10/17 06:59:48 jonas@stripped[jonas] +6 -6
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp
1.37 05/10/13 10:52:15 jonas@stripped[jonas] +227 -34
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
1.95 05/10/25 10:09:00 jonas@stripped[jonas] +1011 -331
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbDictionary.cpp
1.43 05/10/25 10:09:00 jonas@stripped[jonas] +446 -17
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/NdbBlob.cpp
1.30 05/10/25 10:09:00 jonas@stripped[jonas] +6 -5
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/Ndb.cpp
1.61 05/10/25 10:09:00 jonas@stripped[jonas] +10 -10
Import ndb varsize/dd except mysql disk part
storage/ndb/src/ndbapi/DictCache.cpp
1.18 05/10/13 10:52:15 jonas@stripped[jonas] +8 -9
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/pc.hpp
1.11 05/10/13 10:52:15 jonas@stripped[jonas] +8 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/SimulatedBlock.hpp
1.17 05/10/13 10:52:15 jonas@stripped[jonas] +12 -8
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/SimulatedBlock.cpp
1.25 05/10/25 10:09:00 jonas@stripped[jonas] +47 -6
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/SimBlockList.hpp
1.3 05/10/13 10:52:15 jonas@stripped[jonas] +0 -3
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/SafeCounter.cpp
1.6 05/10/25 10:09:00 jonas@stripped[jonas] +1 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/SLList.hpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +68 -40
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/Makefile.am
1.11 05/10/13 10:52:15 jonas@stripped[jonas] +4 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/LongSignal.hpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +1 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/KeyDescriptor.hpp
1.3 05/10/13 10:52:15 jonas@stripped[jonas] +4 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/GlobalData.hpp
1.6 05/10/13 10:52:15 jonas@stripped[jonas] +5 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/DataBuffer.hpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +2 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/DLList.hpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +73 -60
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/DLHashTable.hpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +64 -64
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/DLFifoList.hpp
1.5 05/10/25 10:09:00 jonas@stripped[jonas] +158 -50
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/Configuration.cpp
1.45 05/10/25 10:09:00 jonas@stripped[jonas] +9 -12
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/vm/ArrayPool.hpp
1.9 05/10/13 10:52:15 jonas@stripped[jonas] +20 -10
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/suma/Suma.cpp
1.30 05/10/25 10:09:00 jonas@stripped[jonas] +14 -14
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/ndbfs/OpenFiles.hpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +2 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.hpp
1.6 05/10/13 10:52:15 jonas@stripped[jonas] +5 -3
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp
1.22 05/10/13 10:52:15 jonas@stripped[jonas] +198 -114
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/ndbfs/Filename.hpp
1.7 05/10/13 10:52:15 jonas@stripped[jonas] +20 -22
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/ndbfs/Filename.cpp
1.10 05/10/13 10:52:15 jonas@stripped[jonas] +39 -66
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp
1.7 05/10/13 10:52:15 jonas@stripped[jonas] +10 -4
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp
1.23 05/10/13 10:52:15 jonas@stripped[jonas] +140 -42
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
1.26 05/10/25 10:09:00 jonas@stripped[jonas] +14 -4
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp
1.15 05/10/13 10:52:15 jonas@stripped[jonas] +9 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtux/Makefile.am
1.9 05/10/13 10:52:15 jonas@stripped[jonas] +2 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
1.31 05/10/25 10:09:00 jonas@stripped[jonas] +22 -22
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
1.21 05/10/25 10:09:00 jonas@stripped[jonas] +2 -4
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
1.20 05/10/25 10:09:00 jonas@stripped[jonas] +3 -5
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
1.23 05/10/25 10:09:00 jonas@stripped[jonas] +2 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
1.24 05/10/25 10:09:00 jonas@stripped[jonas] +2 -33
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
1.43 05/10/13 10:52:15 jonas@stripped[jonas] +8 -17
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/Makefile.am
1.7 05/10/13 10:52:15 jonas@stripped[jonas] +14 -4
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp
1.15 05/10/17 06:59:48 jonas@stripped[jonas] +272 -224
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +4 -4
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp
1.3 05/10/13 10:52:15 jonas@stripped[jonas] +22 -20
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp
1.6 05/10/13 10:52:15 jonas@stripped[jonas] +173 -85
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp
1.23 05/10/13 10:52:15 jonas@stripped[jonas] +1088 -668
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupPageMap.cpp
1.3 05/10/13 10:52:15 jonas@stripped[jonas] +19 -19
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupPagMan.cpp
1.7 05/10/13 10:52:15 jonas@stripped[jonas] +43 -44
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
1.16 05/10/25 10:09:00 jonas@stripped[jonas] +713 -336
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
1.15 05/10/13 10:52:15 jonas@stripped[jonas] +355 -246
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp
1.22 05/10/13 10:52:15 jonas@stripped[jonas] +104 -731
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupFixAlloc.cpp
1.3 05/10/13 10:52:15 jonas@stripped[jonas] +86 -278
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
1.22 05/10/25 10:09:00 jonas@stripped[jonas] +2057 -1164
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp
1.10 05/10/13 10:52:15 jonas@stripped[jonas] +92 -83
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +578 -501
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupBuffer.cpp
1.10 05/10/13 10:52:15 jonas@stripped[jonas] +81 -80
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp
1.4 05/10/25 10:09:00 jonas@stripped[jonas] +140 -255
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
1.29 05/10/17 06:59:48 jonas@stripped[jonas] +1218 -956
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtup/AttributeOffset.hpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +7 -7
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
1.93 05/10/25 10:09:00 jonas@stripped[jonas] +11 -5
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp
1.13 05/10/13 10:52:15 jonas@stripped[jonas] +12 -12
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
1.33 05/10/13 10:52:15 jonas@stripped[jonas] +3 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
1.80 05/10/13 10:52:15 jonas@stripped[jonas] +1425 -2277
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp
1.18 05/10/13 10:52:15 jonas@stripped[jonas] +19 -44
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
1.40 05/10/13 10:52:15 jonas@stripped[jonas] +169 -145
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbdih/Sysfile.hpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +6 -6
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbdih/Makefile.am
1.7 05/10/13 10:52:15 jonas@stripped[jonas] +10 -6
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
1.38 05/10/13 10:52:15 jonas@stripped[jonas] +14 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp
1.11 05/10/13 10:52:15 jonas@stripped[jonas] +9 -21
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp
1.12 05/10/13 10:52:15 jonas@stripped[jonas] +14 -4
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbdict/Makefile.am
1.7 05/10/13 10:52:15 jonas@stripped[jonas] +8 -3
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
1.22 05/10/13 10:52:15 jonas@stripped[jonas] +492 -120
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
1.62 05/10/25 10:09:00 jonas@stripped[jonas] +3533 -670
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
1.62 05/10/13 10:52:15 jonas@stripped[jonas] +347 -4439
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp
1.19 05/10/13 10:52:15 jonas@stripped[jonas] +2 -99
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp
1.25 05/10/13 10:52:15 jonas@stripped[jonas] +27 -407
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
1.24 05/10/13 10:52:15 jonas@stripped[jonas] +5 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/backup/read.cpp
1.6 05/10/13 10:52:15 jonas@stripped[jonas] +52 -7
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/backup/Makefile.am
1.7 05/10/13 10:52:15 jonas@stripped[jonas] +8 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/backup/FsBuffer.hpp
1.6 05/10/13 10:52:15 jonas@stripped[jonas] +17 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/backup/BackupInit.cpp
1.17 05/10/25 10:09:00 jonas@stripped[jonas] +106 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/backup/BackupFormat.hpp
1.3 05/10/13 10:52:15 jonas@stripped[jonas] +13 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/backup/Backup.txt
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +62 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/backup/Backup.hpp
1.13 05/10/13 10:52:15 jonas@stripped[jonas] +48 -18
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/backup/Backup.cpp
1.28 05/10/25 10:09:00 jonas@stripped[jonas] +467 -248
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/blocks/Makefile.am
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +19 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/SimBlockList.cpp
1.13 05/10/25 10:09:00 jonas@stripped[jonas] +28 -24
Import ndb varsize/dd except mysql disk part
storage/ndb/src/kernel/Makefile.am
1.14 05/10/13 10:52:15 jonas@stripped[jonas] +4 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/common/debugger/signaldata/TuxMaint.cpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +1 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +5 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/common/debugger/signaldata/SignalNames.cpp
1.9 05/10/13 10:52:15 jonas@stripped[jonas] +27 -30
Import ndb varsize/dd except mysql disk part
storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp
1.13 05/10/13 10:52:15 jonas@stripped[jonas] +1 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/src/common/debugger/signaldata/ScanTab.cpp
1.17 05/10/13 10:52:15 jonas@stripped[jonas] +3 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/src/common/debugger/signaldata/LqhKey.cpp
1.3 05/10/25 10:09:00 jonas@stripped[jonas] +3 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/src/common/debugger/signaldata/FsReadWriteReq.cpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +8 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp
1.8 05/10/13 10:52:15 jonas@stripped[jonas] +92 -3
Import ndb varsize/dd except mysql disk part
storage/ndb/src/common/debugger/BlockNames.cpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +5 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/include/util/UtilBuffer.hpp
1.6 05/10/13 10:52:15 jonas@stripped[jonas] +4 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/include/util/Bitmask.hpp
1.18 05/10/13 10:52:15 jonas@stripped[jonas] +38 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/include/util/BaseString.hpp
1.9 05/10/13 10:52:15 jonas@stripped[jonas] +12 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/include/ndbapi/NdbRecAttr.hpp
1.18 05/10/13 10:52:15 jonas@stripped[jonas] +13 -45
Import ndb varsize/dd except mysql disk part
storage/ndb/include/ndbapi/NdbOperation.hpp
1.34 05/10/13 10:52:15 jonas@stripped[jonas] +68 -33
Import ndb varsize/dd except mysql disk part
storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp
1.23 05/10/13 10:52:15 jonas@stripped[jonas] +28 -6
Import ndb varsize/dd except mysql disk part
storage/ndb/include/ndbapi/NdbDictionary.hpp
1.57 05/10/13 10:52:15 jonas@stripped[jonas] +226 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/include/ndb_constants.h
1.12 05/10/13 10:52:14 jonas@stripped[jonas] +16 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/trigger_definitions.h
1.6 05/10/13 10:52:14 jonas@stripped[jonas] +12 -10
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/TuxMaint.hpp
1.6 05/10/13 10:52:15 jonas@stripped[jonas] +5 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/TupKey.hpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +2 -4
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/TupFrag.hpp
1.9 05/10/13 10:52:15 jonas@stripped[jonas] +2 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/TcKeyReq.hpp
1.7 05/10/13 10:52:15 jonas@stripped[jonas] +18 -37
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/StartFragReq.hpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +1 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/ScanTab.hpp
1.16 05/10/13 10:52:15 jonas@stripped[jonas] +19 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/ScanFrag.hpp
1.12 05/10/13 10:52:15 jonas@stripped[jonas] +18 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/LqhKey.hpp
1.3 05/10/13 10:52:15 jonas@stripped[jonas] +22 -3
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/LqhFrag.hpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +13 -13
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/LCP.hpp
1.3 05/10/13 10:52:15 jonas@stripped[jonas] +66 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/KeyInfo.hpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +1 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/GetTabInfo.hpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +8 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/FsRef.hpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +11 -6
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/FsReadWriteReq.hpp
1.3 05/10/13 10:52:15 jonas@stripped[jonas] +21 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/FsOpenReq.hpp
1.4 05/10/13 10:52:15 jonas@stripped[jonas] +57 -4
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/FsConf.hpp
1.3 05/10/13 10:52:15 jonas@stripped[jonas] +9 -5
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/FsCloseReq.hpp
1.5 05/10/13 10:52:15 jonas@stripped[jonas] +3 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/DumpStateOrd.hpp
1.6 05/10/25 10:09:00 jonas@stripped[jonas] +7 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/DictTabInfo.hpp
1.22 05/10/13 10:52:14 jonas@stripped[jonas] +163 -15
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/CreateTable.hpp
1.5 05/10/13 10:52:14 jonas@stripped[jonas] +5 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/CreateIndx.hpp
1.8 05/10/13 10:52:14 jonas@stripped[jonas] +1 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/BackupImpl.hpp
1.6 05/10/13 10:52:14 jonas@stripped[jonas] +8 -2
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/AttrInfo.hpp
1.4 05/10/13 10:52:14 jonas@stripped[jonas] +1 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/signaldata/AlterTable.hpp
1.6 05/10/13 10:52:14 jonas@stripped[jonas] +17 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/ndb_limits.h
1.19 05/10/13 10:52:14 jonas@stripped[jonas] +11 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/kernel_types.h
1.6 05/10/25 10:09:00 jonas@stripped[jonas] +32 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/GlobalSignalNumbers.h
1.13 05/10/13 10:52:14 jonas@stripped[jonas] +87 -38
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/BlockNumbers.h
1.6 05/10/13 10:52:14 jonas@stripped[jonas] +9 -1
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/AttributeHeader.hpp
1.12 05/10/13 10:52:14 jonas@stripped[jonas] +1 -0
Import ndb varsize/dd except mysql disk part
storage/ndb/include/kernel/AttributeDescriptor.hpp
1.8 05/10/13 10:52:14 jonas@stripped[jonas] +43 -16
Import ndb varsize/dd except mysql disk part
sql/ha_ndbcluster.cc
1.220 05/10/25 10:08:59 jonas@stripped[jonas] +274 -43
Import ndb varsize/dd except mysql disk part
mysql-test/t/ndb_restore.test
1.11 05/10/13 10:52:12 jonas@stripped[jonas] +2 -1
Import ndb varsize/dd except mysql disk part
mysql-test/t/ndb_autodiscover.test
1.23 05/10/13 10:52:12 jonas@stripped[jonas] +2 -2
Import ndb varsize/dd except mysql disk part
mysql-test/t/ndb_alter_table.test
1.27 05/10/13 10:52:12 jonas@stripped[jonas] +4 -4
Import ndb varsize/dd except mysql disk part
mysql-test/r/ndb_restore.result
1.6 05/10/13 10:52:12 jonas@stripped[jonas] +0 -20
Import ndb varsize/dd except mysql disk part
mysql-test/r/ndb_partition_key.result
1.6 05/10/13 10:52:12 jonas@stripped[jonas] +4 -4
Import ndb varsize/dd except mysql disk part
mysql-test/r/ndb_autodiscover.result
1.28 05/10/13 10:52:12 jonas@stripped[jonas] +2 -2
Import ndb varsize/dd except mysql disk part
mysql-test/r/ndb_alter_table.result
1.32 05/10/13 10:52:12 jonas@stripped[jonas] +4 -4
Import ndb varsize/dd except mysql disk part
mysql-test/ndb/ndbcluster.sh
1.43 05/10/13 10:52:12 jonas@stripped[jonas] +1 -1
Import ndb varsize/dd except mysql disk part
configure.in
1.307 05/10/25 10:08:59 jonas@stripped[jonas] +2 -1
Import ndb varsize/dd except mysql disk part
# 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: perch.ndb.mysql.com
# Root: /home/jonas/src/51-clean
--- 1.306/configure.in 2005-10-22 01:02:45 +02:00
+++ 1.307/configure.in 2005-10-25 10:08:59 +02:00
@@ -1813,7 +1813,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.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-13 10:52:15 +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 ---
+++ storage/ndb/include/kernel/signaldata/CreateFilegroup.hpp 05/10/25 14:18:27
/* 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/25 14:18:27
/* 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/25 14:18:27
/* 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/25 14:18:27
/* 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/25 14:18:27
/* 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/25 14:18:28
/* 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/25 14:18:28
/* 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/25 14:18:28
/* 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/25 14:18:28
/* 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/25 14:18:28
/* 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 {
STATS_LOOP = 0,
BUSY_LOOP = 1,
CLEANUP_LOOP = 2,
LCP_LOOP = 3
};
};
#endif
--- New file ---
+++ storage/ndb/include/kernel/signaldata/RestoreContinueB.hpp 05/10/25 14:18:29
/* 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/25 14:18:29
/* 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/25 14:18:29
/* 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/25 14:18:29
/* 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/25 14:18:29
/* 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;
}
}
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/25 14:18:29
/* 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(©_pos_array[0], regTabPtr);
init_var_pos_array(©_pos_array[0],
©_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/25 14:18:30
/* 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/25 14:18:30
/* 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/25 14:18:30
#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/25 14:18:30
/* 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/25 14:18:30
/* 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/25 14:18:30
#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/25 14:18:31
/* 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/25 14:18:31
/* 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;
/**
* Read first page from each undofile (1 file at a time...)
*/
LocalDLFifoList<Undofile> files(m_file_pool, ptr.p->m_meta_files);
Ptr<Undofile> file_ptr;
files.first(file_ptr);
if(!file_ptr.isNull())
{
/**
* Use log buffer memory when reading
*/
Uint32 page_id = ptr.p->m_pos[CONSUMER].m_current_pos.m_ptr_i;
file_ptr.p->m_online.m_outstanding= page_id;
FsReadWriteReq* req= (FsReadWriteReq*)signal->getDataPtrSend();
req->filePointer = file_ptr.p->m_fd;
req->userReference = reference();
req->userPointer = file_ptr.i;
req->varIndex = 1; // skip zero page
req->numberOfPages = 1;
req->data.pageData[0] = page_id;
req->operationFlag = 0;
FsReadWriteReq::setFormatFlag(req->operationFlag,
FsReadWriteReq::fsFormatGlobalPage);
sendSignal(NDBFS_REF, GSN_FSREADREQ, signal,
FsReadWriteReq::FixedLength + 1, JBA);
ptr.p->m_outstanding_fs++;
file_ptr.p->m_state |= Undofile::FS_OUTSTANDING;
return;
}
else
{
/**
* All files have read first page
* and m_files is sorted acording to lsn
*/
ndbassert(!ptr.p->m_files.isEmpty());
LocalDLFifoList<Undofile> read_files(m_file_pool, ptr.p->m_files);
read_files.last(file_ptr);
/**
* Init binary search
*/
ptr.p->m_state = Logfile_group::LG_SEARCHING;
file_ptr.p->m_state = Undofile::FS_SEARCHING;
ptr.p->m_file_pos[TAIL].m_idx = 1; // left page
ptr.p->m_file_pos[HEAD].m_idx = file_ptr.p->m_file_size;
ptr.p->m_file_pos[HEAD].m_ptr_i = ((file_ptr.p->m_file_size - 1) >> 1) +
1;
Uint32 page_id = ptr.p->m_pos[CONSUMER].m_current_pos.m_ptr_i;
file_ptr.p->m_online.m_outstanding= page_id;
FsReadWriteReq* req= (FsReadWriteReq*)signal->getDataPtrSend();
req->filePointer = file_ptr.p->m_fd;
req->userReference = reference();
req->userPointer = file_ptr.i;
req->varIndex = ptr.p->m_file_pos[HEAD].m_ptr_i;
req->numberOfPages = 1;
req->data.pageData[0] = page_id;
req->operationFlag = 0;
FsReadWriteReq::setFormatFlag(req->operationFlag,
FsReadWriteReq::fsFormatGlobalPage);
sendSignal(NDBFS_REF, GSN_FSREADREQ, signal,
FsReadWriteReq::FixedLength + 1, JBA);
ptr.p->m_outstanding_fs++;
file_ptr.p->m_state |= Undofile::FS_OUTSTANDING;
return;
}
}
void
Lgman::execFSREADCONF(Signal* signal)
{
jamEntry();
Ptr<Undofile> ptr;
Ptr<Logfile_group> lg_ptr;
FsConf* conf = (FsConf*)signal->getDataPtr();
m_file_pool.getPtr(ptr, conf->userPointer);
m_logfile_group_pool.getPtr(lg_ptr, ptr.p->m_logfile_group_ptr_i);
ndbassert(ptr.p->m_state & Undofile::FS_OUTSTANDING);
ptr.p->m_state &= ~(Uint32)Undofile::FS_OUTSTANDING;
Uint32 cnt= lg_ptr.p->m_outstanding_fs;
ndbassert(cnt);
if((ptr.p->m_state & Undofile::FS_EXECUTING)== Undofile::FS_EXECUTING)
{
jam();
if(lg_ptr.p->m_next_reply_ptr_i == ptr.i)
{
Uint32 tot= 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--;
if((state & Undofile::FS_MOVE_NEXT) && !files.prev(ptr))
files.last(ptr);
}
lg_ptr.p->m_outstanding_fs = cnt;
lg_ptr.p->m_pos[PRODUCER].m_current_pos.m_idx += tot;
lg_ptr.p->m_next_reply_ptr_i = ptr.i;
}
return;
}
lg_ptr.p->m_outstanding_fs = cnt - 1;
Ptr<GlobalPage> page_ptr;
m_global_page_pool.getPtr(page_ptr, ptr.p->m_online.m_outstanding);
ptr.p->m_online.m_outstanding= 0;
File_formats::Undofile::Undo_page* page =
(File_formats::Undofile::Undo_page*)page_ptr.p;
Uint64 lsn = 0;
lsn += page->m_page_header.m_page_lsn_hi; lsn <<= 32;
lsn += page->m_page_header.m_page_lsn_lo;
switch(ptr.p->m_state){
case Undofile::FS_SORTING:
jam();
break;
case Undofile::FS_SEARCHING:
jam();
find_log_head_in_file(signal, lg_ptr, ptr, lsn);
return;
default:
case Undofile::FS_EXECUTING:
case Undofile::FS_CREATING:
case Undofile::FS_DROPPING:
case Undofile::FS_ONLINE:
case Undofile::FS_OPENING:
case Undofile::FS_EMPTY:
jam();
ndbrequire(false);
}
/**
* Prepare for execution
*/
ptr.p->m_state = Undofile::FS_EXECUTING;
ptr.p->m_online.m_lsn = lsn;
/**
* Insert into m_files
*/
{
LocalDLFifoList<Undofile> meta(m_file_pool, lg_ptr.p->m_meta_files);
LocalDLFifoList<Undofile> files(m_file_pool, lg_ptr.p->m_files);
meta.remove(ptr);
Ptr<Undofile> loop;
files.first(loop);
while(!loop.isNull() && loop.p->m_online.m_lsn <= lsn)
files.next(loop);
if(loop.isNull())
{
/**
* File has highest lsn, add last
*/
jam();
files.add(ptr);
}
else
{
/**
* Insert file in correct position in file list
*/
files.insert(ptr, loop);
}
}
find_log_head(signal, lg_ptr);
}
void
Lgman::execFSREADREF(Signal* signal)
{
jamEntry();
SimulatedBlock::execFSREADREF(signal);
ndbrequire(false);
}
void
Lgman::find_log_head_in_file(Signal* signal,
Ptr<Logfile_group> ptr,
Ptr<Undofile> file_ptr,
Uint64 last_lsn)
{
// a b
// 3 4 5 0 1
Uint32 curr= ptr.p->m_file_pos[HEAD].m_ptr_i;
Uint32 head= ptr.p->m_file_pos[HEAD].m_idx;
Uint32 tail= ptr.p->m_file_pos[TAIL].m_idx;
ndbassert(head > tail);
Uint32 diff = head - tail;
if(DEBUG_SEARCH_LOG_HEAD)
printf("tail: %d(%lld) head: %d last: %d(%lld) -> ",
tail, file_ptr.p->m_online.m_lsn,
head, curr, last_lsn);
if(last_lsn > file_ptr.p->m_online.m_lsn)
{
if(DEBUG_SEARCH_LOG_HEAD)
printf("moving tail ");
file_ptr.p->m_online.m_lsn = last_lsn;
ptr.p->m_file_pos[TAIL].m_idx = tail = curr;
}
else
{
if(DEBUG_SEARCH_LOG_HEAD)
printf("moving head ");
ptr.p->m_file_pos[HEAD].m_idx = head = curr;
}
if(diff > 1)
{
// We need to find more pages to be sure...
ptr.p->m_file_pos[HEAD].m_ptr_i = curr = ((head + tail) >> 1);
if(DEBUG_SEARCH_LOG_HEAD)
ndbout_c("-> new search tail: %d(%lld) head: %d -> %d",
tail, file_ptr.p->m_online.m_lsn,
head, curr);
Uint32 page_id = ptr.p->m_pos[CONSUMER].m_current_pos.m_ptr_i;
file_ptr.p->m_online.m_outstanding= page_id;
FsReadWriteReq* req= (FsReadWriteReq*)signal->getDataPtrSend();
req->filePointer = file_ptr.p->m_fd;
req->userReference = reference();
req->userPointer = file_ptr.i;
req->varIndex = curr;
req->numberOfPages = 1;
req->data.pageData[0] = page_id;
req->operationFlag = 0;
FsReadWriteReq::setFormatFlag(req->operationFlag,
FsReadWriteReq::fsFormatGlobalPage);
sendSignal(NDBFS_REF, GSN_FSREADREQ, signal,
FsReadWriteReq::FixedLength + 1, JBA);
ptr.p->m_outstanding_fs++;
file_ptr.p->m_state |= Undofile::FS_OUTSTANDING;
return;
}
ndbrequire(diff == 1);
if(DEBUG_SEARCH_LOG_HEAD)
ndbout_c("-> found last page: %d", tail);
ptr.p->m_state = 0;
file_ptr.p->m_state = Undofile::FS_EXECUTING;
ptr.p->m_last_lsn = file_ptr.p->m_online.m_lsn;
ptr.p->m_last_read_lsn = file_ptr.p->m_online.m_lsn;
ptr.p->m_last_synced_lsn = file_ptr.p->m_online.m_lsn;
m_last_lsn = file_ptr.p->m_online.m_lsn;
/**
* Set HEAD position
*/
ptr.p->m_file_pos[HEAD].m_ptr_i = file_ptr.i;
ptr.p->m_file_pos[HEAD].m_idx = tail;
ptr.p->m_file_pos[TAIL].m_ptr_i = file_ptr.i;
ptr.p->m_file_pos[TAIL].m_idx = tail - 1;
ptr.p->m_next_reply_ptr_i = file_ptr.i;
{
LocalDLFifoList<Undofile> files(m_file_pool, ptr.p->m_files);
if(tail == 1)
{
/**
* HEAD is first page in a file...
* -> PREV should be in previous file
*/
Ptr<Undofile> prev = file_ptr;
if(!files.prev(prev))
{
files.last(prev);
}
ptr.p->m_file_pos[TAIL].m_ptr_i = prev.i;
ptr.p->m_file_pos[TAIL].m_idx = prev.p->m_file_size - 1;
ptr.p->m_next_reply_ptr_i = prev.i;
}
SimulatedBlock* fs = globalData.getBlock(NDBFS);
infoEvent("Undo head - %s page: %d lsn: %lld",
fs->get_filename(file_ptr.p->m_fd),
tail, file_ptr.p->m_online.m_lsn);
g_eventLogger.info("Undo head - %s page: %d lsn: %lld",
fs->get_filename(file_ptr.p->m_fd),
tail, file_ptr.p->m_online.m_lsn);
for(files.prev(file_ptr); !file_ptr.isNull(); files.prev(file_ptr))
{
infoEvent(" - next - %s(%lld)",
fs->get_filename(file_ptr.p->m_fd),
file_ptr.p->m_online.m_lsn);
g_eventLogger.info(" - next - %s(%lld)",
fs->get_filename(file_ptr.p->m_fd),
file_ptr.p->m_online.m_lsn);
}
}
/**
* Start next logfile group
*/
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);
}
void
Lgman::init_run_undo_log(Signal* signal)
{
/**
* Perform initial sorting of logfile groups
*/
Ptr<Logfile_group> group;
DLFifoList<Logfile_group>& list= m_logfile_group_list;
DLFifoList<Logfile_group> tmp(m_logfile_group_pool);
list.first(group);
while(!group.isNull())
{
Ptr<Logfile_group> ptr= group;
list.next(group);
list.remove(ptr);
{
/**
* Init buffer pointers
*/
ptr.p->m_free_buffer_words -= File_formats::UNDO_PAGE_WORDS;
ptr.p->m_pos[CONSUMER].m_current_page.m_idx = 0; // 0 more pages read
ptr.p->m_pos[PRODUCER].m_current_page.m_idx = 0; // 0 more pages read
Uint32 page = ptr.p->m_pos[CONSUMER].m_current_pos.m_ptr_i;
File_formats::Undofile::Undo_page* pageP =
(File_formats::Undofile::Undo_page*)m_global_page_pool.getPtr(page);
ptr.p->m_pos[CONSUMER].m_current_pos.m_idx = pageP->m_words_used;
ptr.p->m_pos[PRODUCER].m_current_pos.m_idx = 1;
ptr.p->m_last_read_lsn++;
}
/**
* Start producer thread
*/
signal->theData[0] = LgmanContinueB::READ_UNDO_LOG;
signal->theData[1] = ptr.i;
sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
/**
* Insert in correct postion in list of logfile_group's
*/
Ptr<Logfile_group> pos;
for(tmp.first(pos); !pos.isNull(); tmp.next(pos))
if(ptr.p->m_last_read_lsn >= pos.p->m_last_read_lsn)
break;
if(pos.isNull())
tmp.add(ptr);
else
tmp.insert(ptr, pos);
ptr.p->m_state =
Logfile_group::LG_EXEC_THREAD | Logfile_group::LG_READ_THREAD;
}
list = tmp;
execute_undo_record(signal);
}
void
Lgman::read_undo_log(Signal* signal, Ptr<Logfile_group> ptr)
{
Uint32 cnt, free= ptr.p->m_free_buffer_words;
if(! (ptr.p->m_state & Logfile_group::LG_EXEC_THREAD))
{
jam();
/**
* Logfile_group is done...
*/
ptr.p->m_state &= ~(Uint32)Logfile_group::LG_READ_THREAD;
stop_run_undo_log(signal);
return;
}
if(free <= File_formats::UNDO_PAGE_WORDS)
{
signal->theData[0] = LgmanContinueB::READ_UNDO_LOG;
signal->theData[1] = ptr.i;
sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 2);
return;
}
Logfile_group::Position producer= ptr.p->m_pos[PRODUCER];
Logfile_group::Position consumer= ptr.p->m_pos[CONSUMER];
if(producer.m_current_page.m_idx == 0)
{
/**
* zero pages left in range -> switch range
*/
Lgman::Page_map::Iterator it;
Page_map map(m_data_buffer_pool, ptr.p->m_buffer_pages);
Uint32 sz = map.getSize();
Uint32 pos= (producer.m_current_page.m_ptr_i + sz - 2) % sz;
map.position(it, pos);
union {
Uint32 _tmp[2];
Lgman::Buffer_idx range;
};
_tmp[0] = *it.data; map.next(it); _tmp[1] = *it.data;
producer.m_current_page.m_ptr_i = pos;
producer.m_current_page.m_idx = range.m_idx;
producer.m_current_pos.m_ptr_i = range.m_ptr_i + range.m_idx;
}
if(producer.m_current_page.m_ptr_i == consumer.m_current_page.m_ptr_i &&
producer.m_current_pos.m_ptr_i > consumer.m_current_pos.m_ptr_i)
{
Uint32 max=
producer.m_current_pos.m_ptr_i - consumer.m_current_pos.m_ptr_i - 1;
ndbassert(free >= max * File_formats::UNDO_PAGE_WORDS);
cnt= read_undo_pages(signal, ptr, producer.m_current_pos.m_ptr_i, max);
ndbassert(cnt <= max);
producer.m_current_pos.m_ptr_i -= cnt;
producer.m_current_page.m_idx -= cnt;
}
else
{
Uint32 max= producer.m_current_page.m_idx;
ndbassert(free >= max * File_formats::UNDO_PAGE_WORDS);
cnt= read_undo_pages(signal, ptr, producer.m_current_pos.m_ptr_i, max);
ndbassert(cnt <= max);
producer.m_current_pos.m_ptr_i -= cnt;
producer.m_current_page.m_idx -= cnt;
}
ndbassert(free >= cnt * File_formats::UNDO_PAGE_WORDS);
free -= (cnt * File_formats::UNDO_PAGE_WORDS);
ptr.p->m_free_buffer_words = free;
ptr.p->m_pos[PRODUCER] = producer;
signal->theData[0] = LgmanContinueB::READ_UNDO_LOG;
signal->theData[1] = ptr.i;
if(free > File_formats::UNDO_PAGE_WORDS)
sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
else
sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 2);
}
Uint32
Lgman::read_undo_pages(Signal* signal, Ptr<Logfile_group> ptr,
Uint32 pageId, Uint32 pages)
{
ndbassert(pages);
Ptr<Undofile> filePtr;
Buffer_idx tail= ptr.p->m_file_pos[TAIL];
m_file_pool.getPtr(filePtr, tail.m_ptr_i);
if(filePtr.p->m_online.m_outstanding > 0)
{
jam();
return 0;
}
Uint32 max= tail.m_idx;
FsReadWriteReq* req= (FsReadWriteReq*)signal->getDataPtrSend();
req->filePointer = filePtr.p->m_fd;
req->userReference = reference();
req->userPointer = filePtr.i;
req->operationFlag = 0;
FsReadWriteReq::setFormatFlag(req->operationFlag,
FsReadWriteReq::fsFormatGlobalPage);
if(max > pages)
{
jam();
tail.m_idx -= pages;
req->varIndex = 1 + tail.m_idx;
req->numberOfPages = pages;
req->data.pageData[0] = pageId - pages;
ptr.p->m_file_pos[TAIL] = tail;
if(DEBUG_UNDO_EXECUTION)
ndbout_c("a reading from file: %d page(%d-%d) into (%d-%d)",
ptr.i, 1 + tail.m_idx, 1+tail.m_idx+pages-1,
pageId - pages, pageId - 1);
sendSignal(NDBFS_REF, GSN_FSREADREQ, signal,
FsReadWriteReq::FixedLength + 1, JBA);
ptr.p->m_outstanding_fs++;
filePtr.p->m_state |= Undofile::FS_OUTSTANDING;
filePtr.p->m_online.m_outstanding = pages;
max = pages;
}
else
{
jam();
ndbassert(tail.m_idx - max == 0);
req->varIndex = 1;
req->numberOfPages = max;
req->data.pageData[0] = pageId - max;
if(DEBUG_UNDO_EXECUTION)
ndbout_c("b reading from file: %d page(%d-%d) into (%d-%d)",
ptr.i, 1 , 1+max-1,
pageId - max, pageId - 1);
sendSignal(NDBFS_REF, GSN_FSREADREQ, signal,
FsReadWriteReq::FixedLength + 1, JBA);
ptr.p->m_outstanding_fs++;
filePtr.p->m_online.m_outstanding = max;
filePtr.p->m_state |= Undofile::FS_OUTSTANDING | Undofile::FS_MOVE_NEXT;
Ptr<Undofile> prev = filePtr;
LocalDLFifoList<Undofile> files(m_file_pool, ptr.p->m_files);
if(!files.prev(prev))
{
jam();
files.last(prev);
}
if(DEBUG_UNDO_EXECUTION)
ndbout_c("changing file from %d to %d", filePtr.i, prev.i);
tail.m_idx= prev.p->m_file_size - 1;
tail.m_ptr_i= prev.i;
ptr.p->m_file_pos[TAIL] = tail;
if(max < pages && filePtr.i != prev.i)
max += read_undo_pages(signal, ptr, pageId - max, pages - max);
}
return max;
}
void
Lgman::execute_undo_record(Signal* signal)
{
Uint64 lsn;
const Uint32* ptr;
Dbtup* tup= (Dbtup*)globalData.getBlock(DBTUP);
if((ptr = get_next_undo_record(&lsn)))
{
Uint32 len= (* ptr) & 0xFFFF;
Uint32 type= (* ptr) >> 16;
Uint32 mask= type & ~(Uint32)File_formats::Undofile::UNDO_NEXT_LSN;
switch(mask){
case File_formats::Undofile::UNDO_END:
stop_run_undo_log(signal);
return;
case File_formats::Undofile::UNDO_LCP:
case File_formats::Undofile::UNDO_LCP_FIRST:
{
Uint32 lcp = * (ptr - len + 1);
if(lcp > m_latest_lcp)
{
// Just ignore
break;
}
if(lcp < m_latest_lcp ||
(lcp == m_latest_lcp &&
mask == File_formats::Undofile::UNDO_LCP_FIRST))
{
stop_run_undo_log(signal);
return;
}
// Fallthrough
}
case File_formats::Undofile::UNDO_TUP_ALLOC:
case File_formats::Undofile::UNDO_TUP_UPDATE:
case File_formats::Undofile::UNDO_TUP_FREE:
case File_formats::Undofile::UNDO_TUP_CREATE:
tup->disk_restart_undo(signal, lsn, mask, ptr - len + 1, len);
return;
default:
ndbrequire(false);
}
}
signal->theData[0] = LgmanContinueB::EXECUTE_UNDO_RECORD;
sendSignal(LGMAN_REF, GSN_CONTINUEB, signal, 1, JBB);
return;
}
const Uint32*
Lgman::get_next_undo_record(Uint64 * this_lsn)
{
Ptr<Logfile_group> ptr;
m_logfile_group_list.first(ptr);
Logfile_group::Position consumer= ptr.p->m_pos[CONSUMER];
Logfile_group::Position producer= ptr.p->m_pos[PRODUCER];
if(producer.m_current_pos.m_idx < 2)
{
jam();
/**
* Wait for fetching pages...
*/
return 0;
}
Uint32 pos = consumer.m_current_pos.m_idx;
Uint32 page = consumer.m_current_pos.m_ptr_i;
File_formats::Undofile::Undo_page* pageP=(File_formats::Undofile::Undo_page*)
m_global_page_pool.getPtr(page);
if(pos == 0)
{
/**
* End of log
*/
pageP->m_data[0] = (File_formats::Undofile::UNDO_END << 16) | 1 ;
pageP->m_page_header.m_page_lsn_hi = 0;
pageP->m_page_header.m_page_lsn_lo = 0;
pos= consumer.m_current_pos.m_idx= pageP->m_words_used = 1;
this_lsn = 0;
return pageP->m_data;
}
Uint32 *record= pageP->m_data + pos - 1;
Uint32 len= (* record) & 0xFFFF;
ndbassert(len);
Uint32 *prev= record - len;
Uint64 lsn = 0;
// Same page
if(((* record) >> 16) & File_formats::Undofile::UNDO_NEXT_LSN)
{
lsn = ptr.p->m_last_read_lsn - 1;
ndbrequire((Int64)lsn >= 0);
}
else
{
ndbassert(pos >= 3);
lsn += * (prev - 1); lsn <<= 32;
lsn += * (prev - 0);
len += 2;
ndbrequire((Int64)lsn >= 0);
}
ndbassert(pos >= len);
if(pos == len)
{
/**
* Switching page
*/
ndbassert(producer.m_current_pos.m_idx);
ptr.p->m_pos[PRODUCER].m_current_pos.m_idx --;
if(consumer.m_current_page.m_idx)
{
consumer.m_current_page.m_idx--; // left in range
consumer.m_current_pos.m_ptr_i --; // page
}
else
{
// 0 pages left in range...switch range
Lgman::Page_map::Iterator it;
Page_map map(m_data_buffer_pool, ptr.p->m_buffer_pages);
Uint32 sz = map.getSize();
Uint32 tmp = (consumer.m_current_page.m_ptr_i + sz - 2) % sz;
map.position(it, tmp);
union {
Uint32 _tmp[2];
Lgman::Buffer_idx range;
};
_tmp[0] = *it.data; map.next(it); _tmp[1] = *it.data;
consumer.m_current_page.m_idx = range.m_idx - 1; // left in range
consumer.m_current_page.m_ptr_i = tmp; // pos in map
consumer.m_current_pos.m_ptr_i = range.m_ptr_i + range.m_idx - 1; // page
}
if(DEBUG_UNDO_EXECUTION)
ndbout_c("reading from %d", consumer.m_current_pos.m_ptr_i);
pageP=(File_formats::Undofile::Undo_page*)
m_global_page_pool.getPtr(consumer.m_current_pos.m_ptr_i);
pos= consumer.m_current_pos.m_idx= pageP->m_words_used;
Uint64 tmp = 0;
tmp += pageP->m_page_header.m_page_lsn_hi; tmp <<= 32;
tmp += pageP->m_page_header.m_page_lsn_lo;
prev = pageP->m_data + pos - 1;
if(((* prev) >> 16) & File_formats::Undofile::UNDO_NEXT_LSN)
ndbassert(lsn + 1 == ptr.p->m_last_read_lsn);
ptr.p->m_pos[CONSUMER] = consumer;
ptr.p->m_free_buffer_words += File_formats::UNDO_PAGE_WORDS;
}
else
{
ptr.p->m_pos[CONSUMER].m_current_pos.m_idx -= len;
}
* this_lsn = ptr.p->m_last_read_lsn = lsn;
/**
* Re-sort log file groups
*/
Ptr<Logfile_group> sort = ptr;
if(m_logfile_group_list.next(sort))
{
while(!sort.isNull() && sort.p->m_last_read_lsn > lsn)
m_logfile_group_list.next(sort);
if(sort.i != ptr.p->nextList)
{
m_logfile_group_list.remove(ptr);
if(sort.isNull())
m_logfile_group_list.add(ptr);
else
m_logfile_group_list.insert(ptr, sort);
}
}
return record;
}
void
Lgman::stop_run_undo_log(Signal* signal)
{
bool running = false, outstanding = false;
Ptr<Logfile_group> ptr;
m_logfile_group_list.first(ptr);
while(!ptr.isNull())
{
/**
* Mark exec thread as completed
*/
ptr.p->m_state &= ~(Uint32)Logfile_group::LG_EXEC_THREAD;
if(ptr.p->m_state & Logfile_group::LG_READ_THREAD)
{
/**
* Thread is still running...wait for it to complete
*/
running = true;
}
else if(ptr.p->m_outstanding_fs)
{
outstanding = true; // a FSREADREQ is outstanding...wait for it
}
else if(ptr.p->m_state != Logfile_group::LG_ONLINE)
{
/**
* Fix log TAIL
*/
ndbassert(ptr.p->m_state == 0);
ptr.p->m_state = Logfile_group::LG_ONLINE;
Buffer_idx tail= ptr.p->m_file_pos[TAIL];
Uint32 pages= ptr.p->m_pos[PRODUCER].m_current_pos.m_idx;
while(pages)
{
Ptr<Undofile> file;
m_file_pool.getPtr(file, tail.m_ptr_i);
Uint32 page= tail.m_idx;
Uint32 size= file.p->m_file_size;
ndbassert(size >= page);
Uint32 diff= size - page;
if(pages >= diff)
{
pages -= diff;
LocalDLFifoList<Undofile> files(m_file_pool, ptr.p->m_files);
if(!files.next(file))
files.first(file);
tail.m_idx = 1;
tail.m_ptr_i= file.i;
}
else
{
tail.m_idx += pages;
pages= 0;
}
}
ptr.p->m_tail_pos[0] = tail;
ptr.p->m_tail_pos[1] = tail;
ptr.p->m_tail_pos[2] = tail;
ptr.p->m_file_pos[TAIL] = tail;
init_logbuffer_pointers(ptr);
ptr.p->m_free_file_words = (Uint64)File_formats::UNDO_PAGE_WORDS *
(Uint64)compute_free_file_pages(ptr);
ptr.p->m_next_reply_ptr_i = ptr.p->m_file_pos[HEAD].m_ptr_i;
signal->theData[0] = LgmanContinueB::FLUSH_LOG;
signal->theData[1] = ptr.i;
sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
if(1)
{
SimulatedBlock* fs = globalData.getBlock(NDBFS);
Ptr<Undofile> hf, tf;
m_file_pool.getPtr(tf, tail.m_ptr_i);
m_file_pool.getPtr(hf, ptr.p->m_file_pos[HEAD].m_ptr_i);
infoEvent("Logfile group: %d ", ptr.p->m_logfile_group_id);
g_eventLogger.info("Logfile group: %d ", ptr.p->m_logfile_group_id);
infoEvent(" head: %s page: %d",
fs->get_filename(hf.p->m_fd),
ptr.p->m_file_pos[HEAD].m_idx);
g_eventLogger.info(" head: %s page: %d",
fs->get_filename(hf.p->m_fd),
ptr.p->m_file_pos[HEAD].m_idx);
infoEvent(" tail: %s page: %d",
fs->get_filename(tf.p->m_fd), tail.m_idx);
g_eventLogger.info(" tail: %s page: %d",
fs->get_filename(tf.p->m_fd), tail.m_idx);
}
}
m_logfile_group_list.next(ptr);
}
if(running)
{
jam();
return;
}
if(outstanding)
{
jam();
signal->theData[0] = LgmanContinueB::STOP_UNDO_LOG;
sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 100, 1);
return;
}
infoEvent("Flushing page cache after undo completion");
g_eventLogger.info("Flushing page cache after undo completion");
/**
* Start flushing pages (local, LCP)
*/
LcpFragOrd * ord = (LcpFragOrd *)signal->getDataPtr();
ord->lcpId = m_latest_lcp;
sendSignal(PGMAN_REF, GSN_LCP_FRAG_ORD, signal,
LcpFragOrd::SignalLength, JBB);
EndLcpReq* req= (EndLcpReq*)signal->getDataPtr();
req->senderRef = reference();
sendSignal(PGMAN_REF, GSN_END_LCP_REQ, signal,
EndLcpReq::SignalLength, JBB);
}
void
Lgman::execEND_LCP_CONF(Signal* signal)
{
/**
* pgman has completed flushing all pages
*
* insert "fake" LCP record preventing undo to be "rerun"
*/
Uint32 undo[3];
undo[0] = m_latest_lcp;
undo[1] = (0 << 16) | 0;
undo[2] = (File_formats::Undofile::UNDO_LCP_FIRST << 16 )
| (sizeof(undo) >> 2);
Ptr<Logfile_group> ptr;
ndbrequire(m_logfile_group_list.first(ptr));
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) + 2));
ptr.p->m_free_file_words -= ((sizeof(undo) >> 2) + 2);
}
m_last_lsn = ptr.p->m_last_lsn = last_lsn + 1;
ptr.p->m_last_synced_lsn = last_lsn;
while(m_logfile_group_list.next(ptr))
ptr.p->m_last_synced_lsn = last_lsn;
infoEvent("Flushing complete");
g_eventLogger.info("Flushing complete");
signal->theData[0] = reference();
sendSignal(DBLQH_REF, GSN_START_RECCONF, signal, 1, JBB);
}
#ifdef VM_TRACE
void
Lgman::validate_logfile_group(Ptr<Logfile_group> ptr, const char * heading)
{
if (ptr.p->m_file_pos[HEAD].m_ptr_i == RNIL)
return;
Uint32 pages = compute_free_file_pages(ptr);
Uint32 group_pages =
((ptr.p->m_free_file_words + File_formats::UNDO_PAGE_WORDS - 1)/
File_formats::UNDO_PAGE_WORDS) ;
Uint32 last = ptr.p->m_free_file_words % File_formats::UNDO_PAGE_WORDS;
if(! (pages >= group_pages))
{
ndbout << heading << " Tail: " << ptr.p->m_file_pos[TAIL]
<< " Head: " << ptr.p->m_file_pos[HEAD]
<< " free: " << group_pages << "(" << last << ")"
<< " found: " << pages;
for(Uint32 i = 0; i<3; i++)
{
ndbout << " - " << ptr.p->m_tail_pos[i];
}
ndbout << endl;
ndbrequire(pages >= group_pages);
}
}
#endif
--- New file ---
+++ storage/ndb/src/kernel/blocks/lgman.hpp 05/10/25 14:18:31
/* 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_H
#define LGMAN_H
#include <SimulatedBlock.hpp>
#include <SLList.hpp>
#include <DLList.hpp>
#include <DLFifoList.hpp>
#include <KeyTable.hpp>
#include <DLHashTable.hpp>
#include <NodeBitmask.hpp>
#include "diskpage.hpp"
class Lgman : public SimulatedBlock
{
public:
Lgman(const Configuration & conf);
virtual ~Lgman();
BLOCK_DEFINES(Lgman);
protected:
void execSTTOR(Signal* signal);
void sendSTTORRY(Signal*);
void execREAD_CONFIG_REQ(Signal* signal);
void execDUMP_STATE_ORD(Signal* signal);
void execCONTINUEB(Signal* signal);
void execCREATE_FILE_REQ(Signal* signal);
void execCREATE_FILEGROUP_REQ(Signal* signal);
void execDROP_FILE_REQ(Signal* signal);
void execDROP_FILEGROUP_REQ(Signal* signal);
void execFSWRITEREQ(Signal*);
void execFSWRITEREF(Signal*);
void execFSWRITECONF(Signal*);
void execFSOPENREF(Signal*);
void execFSOPENCONF(Signal*);
void execFSCLOSEREF(Signal*);
void execFSCLOSECONF(Signal*);
void execFSREADREF(Signal*);
void execFSREADCONF(Signal*);
void execLCP_FRAG_ORD(Signal*);
void execEND_LCP_REQ(Signal*);
void execSUB_GCP_COMPLETE_REP(Signal*);
void execSTART_RECREQ(Signal*);
void execEND_LCP_CONF(Signal*);
public:
struct Log_waiter
{
union {
Uint32 m_size;
Uint64 m_sync_lsn;
};
Uint32 m_block;
Callback m_callback;
union {
Uint32 nextPool;
Uint32 nextList;
};
Uint32 prevList;
};
struct Undofile
{
Undofile(){}
Undofile(const struct CreateFileImplReq*, Uint32 lg_ptr_i);
Uint32 m_file_id; // Dict obj id
Uint32 m_logfile_group_ptr_i;
Uint32 m_file_size;
Uint32 m_state;
Uint32 m_fd; // When speaking to NDBFS
enum FileState
{
FS_CREATING = 0x1 // File is being created
,FS_DROPPING = 0x2 // File is being dropped
,FS_ONLINE = 0x4 // File is online
,FS_OPENING = 0x8 // File is being opened during SR
,FS_SORTING = 0x10 // Files in group are being sorted
,FS_SEARCHING = 0x20 // File is being searched for end of log
,FS_EXECUTING = 0x40 // File is used for executing UNDO log
,FS_EMPTY = 0x80 // File is empty (used when online)
,FS_OUTSTANDING = 0x100 // File has outstanding request
,FS_MOVE_NEXT = 0x200 // When receiving reply move to next file
};
union {
struct {
Uint32 m_outstanding; // Outstaning pages
Uint64 m_lsn; // Used when finding log head
} m_online;
struct {
Uint32 m_senderData;
Uint32 m_senderRef;
Uint32 m_logfile_group_id;
Uint32 m_logfile_group_version;
} m_create;
};
Uint32 nextList;
union {
Uint32 prevList;
Uint32 nextPool;
};
};
typedef LocalDataBuffer<15> Page_map;
struct Buffer_idx
{
Uint32 m_ptr_i;
Uint32 m_idx;
bool operator== (const Buffer_idx& bi) const {
return (m_ptr_i == bi.m_ptr_i && m_idx == bi.m_idx);
}
};
struct Logfile_group
{
Logfile_group(){}
Logfile_group(const struct CreateFilegroupImplReq*);
union {
Uint32 key;
Uint32 m_logfile_group_id;
};
Uint32 m_version;
Uint16 m_state;
Uint16 m_outstanding_fs;
Uint32 m_next_reply_ptr_i;
enum Logfile_group_state
{
LG_ONLINE = 0x001
,LG_SORTING = 0x002 // Sorting files
,LG_SEARCHING = 0x004 // Searching in last file
,LG_EXEC_THREAD = 0x008 // Execute thread is running
,LG_READ_THREAD = 0x010 // Read thread is running
,LG_FORCE_SYNC_THREAD = 0x020
,LG_SYNC_WAITERS_THREAD = 0x040
,LG_CUT_LOG_THREAD = 0x080
,LG_WAITERS_THREAD = 0x100
,LG_FLUSH_THREAD = 0x200
,LG_DROPPING = 0x400
};
static const Uint32 LG_THREAD_MASK = Logfile_group::LG_FORCE_SYNC_THREAD |
Logfile_group::LG_SYNC_WAITERS_THREAD |
Logfile_group::LG_CUT_LOG_THREAD |
Logfile_group::LG_WAITERS_THREAD |
Logfile_group::LG_FLUSH_THREAD;
Uint64 m_last_lsn;
Uint64 m_last_sync_req_lsn;
Uint64 m_last_synced_lsn;
union {
Uint64 m_last_read_lsn;
Uint64 m_last_lcp_lsn;
};
DLFifoList<Log_waiter>::Head m_log_sync_waiters;
Buffer_idx m_tail_pos[3]; // 0 is cut, 1 is saved, 2 is current
Buffer_idx m_file_pos[2]; // 0 tail, 1 head = { file_ptr_i, page_no }
Uint64 m_free_file_words; // Free words in logfile group
DLFifoList<Undofile>::Head m_files; // Files in log
DLFifoList<Undofile>::Head m_meta_files;// Files being created or dropped
Uint32 m_free_buffer_words; // Free buffer page words
DLFifoList<Log_waiter>::Head m_log_buffer_waiters;
Page_map::Head m_buffer_pages; // Pairs of { ptr.i, count }
struct Position {
Buffer_idx m_current_page; // { m_buffer_pages.i, left in range }
Buffer_idx m_current_pos; // { page ptr.i, m_words_used }
} m_pos[2]; // 0 is reader (lgman) 1 is writer (tup)
Uint32 nextHash;
Uint32 prevHash;
Uint32 nextList;
union {
Uint32 prevList;
Uint32 nextPool;
};
Uint32 hashValue() const {
return key;
}
bool equal(const Logfile_group& rec) const {
return key == rec.key;
}
};
/**
* Alloc/free space in log
* Alloction will be removed at either/or
* 1) Logfile_client::add_entry
* 2) free_log_space
*/
int alloc_log_space(Uint32 logfile_ref, Uint32 words);
int free_log_space(Uint32 logfile_ref, Uint32 words);
private:
friend class Logfile_client;
ArrayPool<Undofile> m_file_pool;
ArrayPool<Logfile_group> m_logfile_group_pool;
ArrayPool<Log_waiter> m_log_waiter_pool;
Page_map::DataBufferPool m_data_buffer_pool;
Uint64 m_last_lsn;
Uint32 m_latest_lcp;
DLFifoList<Logfile_group> m_logfile_group_list;
KeyTable<Logfile_group> m_logfile_group_hash;
bool alloc_logbuffer_memory(Ptr<Logfile_group>, Uint32 pages);
void init_logbuffer_pointers(Ptr<Logfile_group>);
void free_logbuffer_memory(Ptr<Logfile_group>);
Uint32 compute_free_file_pages(Ptr<Logfile_group>);
Uint32* get_log_buffer(Ptr<Logfile_group>, Uint32 sz);
void process_log_buffer_waiters(Signal* signal, Ptr<Logfile_group>);
Uint32 next_page(Logfile_group* ptrP, Uint32 i);
void force_log_sync(Signal*, Ptr<Logfile_group>, Uint32 lsnhi, Uint32 lnslo);
void process_log_sync_waiters(Signal* signal, Ptr<Logfile_group>);
void cut_log_tail(Signal*, Ptr<Logfile_group> ptr);
void endlcp_callback(Signal*, Uint32, Uint32);
void open_file(Signal*, Ptr<Undofile>, Uint32 requestInfo);
void flush_log(Signal*, Ptr<Logfile_group>);
Uint32 write_log_pages(Signal*, Ptr<Logfile_group>,
Uint32 pageId, Uint32 pages);
void find_log_head(Signal* signal, Ptr<Logfile_group> ptr);
void find_log_head_in_file(Signal*,
Ptr<Logfile_group>,Ptr<Undofile>,Uint64);
void init_run_undo_log(Signal*);
void read_undo_log(Signal*, Ptr<Logfile_group> ptr);
Uint32 read_undo_pages(Signal*, Ptr<Logfile_group>,
Uint32 pageId, Uint32 pages);
void execute_undo_record(Signal*);
const Uint32* get_next_undo_record(Uint64* lsn);
void stop_run_undo_log(Signal* signal);
void init_tail_ptr(Signal* signal, Ptr<Logfile_group> ptr);
bool find_file_by_id(Ptr<Undofile>&, DLFifoList<Undofile>::Head&,
Uint32 id);
void create_file_commit(Signal* signal, Ptr<Logfile_group>, Ptr<Undofile>);
void create_file_abort(Signal* signal, Ptr<Logfile_group>, Ptr<Undofile>);
#ifdef VM_TRACE
void validate_logfile_group(Ptr<Logfile_group> ptr, const char * = 0);
#else
void validate_logfile_group(Ptr<Logfile_group> ptr, const char * = 0) {}
#endif
void drop_filegroup_drop_files(Signal*, Ptr<Logfile_group>,
Uint32 ref, Uint32 data);
};
class Logfile_client {
Uint32 m_block;
Lgman * m_lgman;
public:
Uint32 m_logfile_group_id;
Logfile_client() {}
Logfile_client(SimulatedBlock* block, Lgman*, Uint32 logfile_group_id);
struct Request
{
SimulatedBlock::Callback m_callback;
};
/**
* Request flags
*/
enum RequestFlags
{
};
/**
* Make sure a lsn is stored
* @return -1, on error
* 0, request in queued
* >0, done
*/
int sync_lsn(Signal*, Uint64, Request*, Uint32 flags);
/**
* Undolog entries
*/
struct Change
{
const void * ptr;
Uint32 len;
};
Uint64 add_entry(const void*, Uint32 len);
template<Uint32 cnt> Uint64 add_entry(const Change*);
Uint64 add_entry(Local_key, void * base, Change*);
Uint64 add_entry(Local_key, Uint32 off, Uint32 change);
/**
* Check for space in log buffer
*
* return >0 if available
* 0 on time slice
* -1 on error
*/
int get_log_buffer(Signal*, Uint32 sz, SimulatedBlock::Callback* m_callback);
private:
Uint32* get_log_buffer(Uint32 sz);
};
#endif
--- New file ---
+++ storage/ndb/src/kernel/blocks/pgman.cpp 05/10/25 14:18:31
/* 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 "pgman.hpp"
#include <signaldata/FsRef.hpp>
#include <signaldata/FsConf.hpp>
#include <signaldata/FsReadWriteReq.hpp>
#include <signaldata/PgmanContinueB.hpp>
#include <signaldata/LCP.hpp>
#include <dbtup/Dbtup.hpp>
#include <DebuggerNames.hpp>
/**
* Requests that make page dirty
*/
#define DIRTY_FLAGS (Page_request::COMMIT_REQ | \
Page_request::DIRTY_REQ | \
Page_request::ALLOC_REQ)
// todo use this
#ifdef VM_TRACE
#define dbg(x) \
do { if (! debugFlag) break; debugOut << "PGMAN: " << x << endl; }
while (0)
#else
#define dbg(x)
#endif
Pgman::Pgman(const Configuration & conf) :
SimulatedBlock(PGMAN, conf),
m_file_map(m_data_buffer_pool),
m_page_hashlist(m_page_entry_pool),
m_page_stack(m_page_entry_pool),
m_page_queue(m_page_entry_pool)
#ifdef VM_TRACE
,debugOut(* new NullOutputStream())
,debugFlag(false)
#endif
{
BLOCK_CONSTRUCTOR(Pgman);
// Add received signals
addRecSignal(GSN_STTOR, &Pgman::execSTTOR);
addRecSignal(GSN_READ_CONFIG_REQ, &Pgman::execREAD_CONFIG_REQ);
addRecSignal(GSN_DUMP_STATE_ORD, &Pgman::execDUMP_STATE_ORD);
addRecSignal(GSN_CONTINUEB, &Pgman::execCONTINUEB);
addRecSignal(GSN_FSREADREF, &Pgman::execFSREADREF, true);
addRecSignal(GSN_FSREADCONF, &Pgman::execFSREADCONF);
addRecSignal(GSN_FSWRITEREF, &Pgman::execFSWRITEREF, true);
addRecSignal(GSN_FSWRITECONF, &Pgman::execFSWRITECONF);
addRecSignal(GSN_LCP_FRAG_ORD, &Pgman::execLCP_FRAG_ORD);
addRecSignal(GSN_END_LCP_REQ, &Pgman::execEND_LCP_REQ);
// loop status
m_stats_loop_on = false;
m_busy_loop_on = false;
m_cleanup_loop_on = false;
m_lcp_loop_on = false;
// LCP variables
m_last_lcp = 0;
m_last_lcp_complete = 0;
m_lcp_curr_bucket = ~(Uint32)0;
m_lcp_outstanding = 0;
m_lcp_copy_page = RNIL;
m_lcp_copy_page_free = false;
// clean-up variables
m_cleanup_ptr.i = RNIL;
// should be a factor larger than number of pool pages
m_page_entry_pool.setSize(2000);
m_page_request_pool.setSize(10000);
m_data_buffer_pool.setSize(1);
m_page_hashlist.setSize(512);
for (Uint32 k = 0; k < Page_entry::SUBLIST_COUNT; k++)
m_page_sublist[k] = new Page_sublist(m_page_entry_pool);
}
Pgman::~Pgman()
{
for (Uint32 k = 0; k < Page_entry::SUBLIST_COUNT; k++)
delete m_page_sublist[k];
}
BLOCK_FUNCTIONS(Pgman)
void
Pgman::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);
}
Pgman::Param::Param() :
m_max_pages(64), // smallish for testing
m_max_hot_pages(56),
m_max_loop_count(256),
m_max_io_waits(64),
m_stats_loop_delay(1000),
m_cleanup_loop_delay(200),
m_lcp_loop_delay(200)
{
}
Pgman::Stats::Stats() :
m_num_pages(0),
m_page_hits(0),
m_page_faults(0),
m_current_io_waits(0)
{
}
void
Pgman::execSTTOR(Signal* signal)
{
jamEntry();
const Uint32 startPhase = signal->theData[1];
switch (startPhase) {
case 1:
{
Lgman* lgman = (Lgman*)globalData.getBlock(LGMAN);
new (&m_lgman) Logfile_client(this, lgman, 0);
c_tup = (Dbtup*)globalData.getBlock(DBTUP);
}
break;
case 3:
{
Ptr<GlobalPage> page_ptr;
ndbrequire(m_global_page_pool.seize(page_ptr));
m_lcp_copy_page = page_ptr.i;
m_lcp_copy_page_free = true;
// start forever loops
do_stats_loop(signal);
do_cleanup_loop(signal);
m_stats_loop_on = true;
m_cleanup_loop_on = true;
}
break;
case 7:
break;
default:
break;
}
sendSTTORRY(signal);
}
void
Pgman::sendSTTORRY(Signal* signal)
{
signal->theData[0] = 0;
signal->theData[3] = 1;
signal->theData[4] = 3;
signal->theData[5] = 7;
signal->theData[6] = 255; // No more start phases from missra
sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 7, JBB);
}
void
Pgman::execCONTINUEB(Signal* signal)
{
jamEntry();
Uint32 data1 = signal->theData[1];
switch (signal->theData[0]) {
case PgmanContinueB::STATS_LOOP:
jam();
do_stats_loop(signal);
break;
case PgmanContinueB::BUSY_LOOP:
jam();
do_busy_loop(signal);
break;
case PgmanContinueB::CLEANUP_LOOP:
jam();
do_cleanup_loop(signal);
break;
case PgmanContinueB::LCP_LOOP:
jam();
do_lcp_loop(signal);
break;
default:
ndbrequire(false);
break;
}
}
// page entry
Pgman::Page_entry::Page_entry(Uint32 file_no, Uint32 page_no) :
m_state(0),
m_file_no(file_no),
m_page_no(page_no),
m_real_page_i(RNIL),
m_lsn(0),
m_last_lcp(0),
m_busy_count(0),
m_requests()
{
}
// page lists
Uint32
Pgman::get_sublist_no(Uint16 state)
{
if (state == 0)
{
return ZNIL;
}
if (state & Page_entry::REQUEST)
{
if (! (state & Page_entry::BOUND))
{
return Page_entry::SL_BIND;
}
if (! (state & Page_entry::MAPPED))
{
if (! (state & Page_entry::PAGEIN))
{
return Page_entry::SL_MAP;
}
return Page_entry::SL_MAP_IO;
}
if (! (state & Page_entry::PAGEOUT))
{
return Page_entry::SL_CALLBACK;
}
return Page_entry::SL_CALLBACK_IO;
}
if (state & Page_entry::BUSY)
{
return Page_entry::SL_BUSY;
}
if (state & Page_entry::LOCKED)
{
return Page_entry::SL_LOCKED;
}
return Page_entry::SL_OTHER;
}
void
Pgman::set_page_state(Ptr<Page_entry> ptr, Uint16 new_state)
{
#ifdef VM_TRACE
debugOut << "PGMAN: >set_page_state: state=" << hex << new_state
<< endl;
debugOut << "PGMAN: " << ptr << ": before" << endl;
#endif
Uint16 old_state = ptr.p->m_state;
if (old_state != new_state)
{
Uint32 old_list_no = get_sublist_no(old_state);
Uint32 new_list_no = get_sublist_no(new_state);
if (old_state != 0)
{
ndbrequire(old_list_no != ZNIL);
if (old_list_no != new_list_no)
{
Page_sublist& old_list = *m_page_sublist[old_list_no];
old_list.remove(ptr);
}
}
if (new_state != 0)
{
ndbrequire(new_list_no != ZNIL);
if (old_list_no != new_list_no)
{
Page_sublist& new_list = *m_page_sublist[new_list_no];
new_list.add(ptr);
}
}
ptr.p->m_state = new_state;
}
#ifdef VM_TRACE
debugOut << "PGMAN: " << ptr << ": after" << endl;
debugOut << "PGMAN: <set_page_state" << endl;
#endif
}
// seize/release pages and entries
bool
Pgman::seize_cache_page(Ptr<GlobalPage>& gptr)
{
// page cache has no own pool yet
bool ok = m_global_page_pool.seize(gptr);
// zero is reserved as return value for queued request
if (ok && gptr.i == 0)
ok = m_global_page_pool.seize(gptr);
if (ok)
{
ndbrequire(m_stats.m_num_pages < m_param.m_max_pages);
m_stats.m_num_pages++;
}
return ok;
}
void
Pgman::release_cache_page(Uint32 i)
{
m_global_page_pool.release(i);
ndbrequire(m_stats.m_num_pages != 0);
m_stats.m_num_pages--;
}
bool
Pgman::find_page_entry(Ptr<Page_entry>& ptr, Uint32 file_no, Uint32 page_no)
{
Page_entry key;
key.m_file_no = file_no;
key.m_page_no = page_no;
if (m_page_hashlist.find(ptr, key))
{
#ifdef VM_TRACE
debugOut << "PGMAN: find_page_entry" << endl;
debugOut << "PGMAN: " << ptr << endl;
#endif
return true;
}
return false;
}
Uint32
Pgman::seize_page_entry(Ptr<Page_entry>& ptr, Uint32 file_no, Uint32 page_no)
{
if (m_page_entry_pool.seize(ptr))
{
new (ptr.p) Page_entry(file_no, page_no);
m_page_hashlist.add(ptr);
#ifdef VM_TRACE
ptr.p->m_this = this;
debugOut << "PGMAN: seize_page_entry" << endl;
debugOut << "PGMAN: " << ptr << endl;
#endif
return true;
}
return false;
}
bool
Pgman::get_page_entry(Ptr<Page_entry>& ptr, Uint32 file_no, Uint32 page_no)
{
if (find_page_entry(ptr, file_no, page_no))
{
ndbrequire(ptr.p->m_state != 0);
m_stats.m_page_hits++;
return true;
}
if (seize_page_entry(ptr, file_no, page_no))
{
ndbrequire(ptr.p->m_state == 0);
m_stats.m_page_faults++;
return true;
}
return false;
}
void
Pgman::release_page_entry(Ptr<Page_entry>& ptr)
{
#ifdef VM_TRACE
debugOut << "PGMAN: release_page_entry" << endl;
debugOut << "PGMAN: " << ptr << endl;
#endif
Uint16 state = ptr.p->m_state;
ndbrequire(! (state & Page_entry::REQUEST));
ndbrequire(ptr.p->m_requests.isEmpty());
| Thread |
|---|
| • bk commit into 5.1 tree (jonas:1.1941) | jonas | 25 Oct |