summaryrefslogtreecommitdiff
path: root/cpp/src/FreezeScript/transformdb.cpp
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2004-01-16 22:22:44 +0000
committerMark Spruiell <mes@zeroc.com>2004-01-16 22:22:44 +0000
commit00081d77200a08baac2e62cc2797c7530caacea3 (patch)
tree69a638dc86939389e9c810946a7d0fef20a31cd4 /cpp/src/FreezeScript/transformdb.cpp
parentadding ClassDef::isA (diff)
downloadice-00081d77200a08baac2e62cc2797c7530caacea3.tar.bz2
ice-00081d77200a08baac2e62cc2797c7530caacea3.tar.xz
ice-00081d77200a08baac2e62cc2797c7530caacea3.zip
initial check-in
Diffstat (limited to 'cpp/src/FreezeScript/transformdb.cpp')
-rw-r--r--cpp/src/FreezeScript/transformdb.cpp645
1 files changed, 645 insertions, 0 deletions
diff --git a/cpp/src/FreezeScript/transformdb.cpp b/cpp/src/FreezeScript/transformdb.cpp
new file mode 100644
index 00000000000..b85365a8cb7
--- /dev/null
+++ b/cpp/src/FreezeScript/transformdb.cpp
@@ -0,0 +1,645 @@
+// **********************************************************************
+//
+// Copyright (c) 2004
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <FreezeScript/Transformer.h>
+#include <FreezeScript/Util.h>
+#include <db_cxx.h>
+#include <sys/stat.h>
+#include <fstream>
+#include <algorithm>
+
+using namespace std;
+
+#ifdef _WIN32
+# define FREEZE_SCRIPT_DB_MODE 0
+#else
+# define FREEZE_SCRIPT_DB_MODE (S_IRUSR | S_IWUSR)
+#endif
+
+static void
+usage(const char* n)
+{
+ cerr << "Usage: " << n << " [options] [dbenv db newdbenv]\n";
+ cerr <<
+ "Options:\n"
+ "-h, --help Show this message.\n"
+ "-v, --version Display the Ice version.\n"
+ "-DNAME Define NAME as 1.\n"
+ "-DNAME=DEF Define NAME as DEF.\n"
+ "-UNAME Remove any definition for NAME.\n"
+ "-d, --debug Print debug messages.\n"
+ "--ice Permit `Ice' prefix (for building Ice source code only)\n"
+ "-o FILE Output transformation descriptors into the file FILE.\n"
+ " Database transformation is not performed.\n"
+ "-i Ignore incompatible type changes.\n"
+ "-p Purge objects whose types no longer exist.\n"
+ "-c Use catastrophic recovery on the old database environment.\n"
+ "-w Suppress duplicate warnings during transformation.\n"
+ "-f FILE Execute the transformation descriptors in the file FILE.\n"
+ "--include-old DIR Put DIR in the include file search path for old Slice\n"
+ " definitions.\n"
+ "--include-new DIR Put DIR in the include file search path for new Slice\n"
+ " definitions.\n"
+ "--old SLICE Load old Slice definitions from the file SLICE.\n"
+ "--new SLICE Load new Slice definitions from the file SLICE.\n"
+ "-e Indicates the database is an Evictor database.\n"
+ "--key TYPE[,TYPE] Specifies the Slice types of the database key. If the\n"
+ " type names have not changed, only one needs to be\n"
+ " specified. Otherwise, the type names are specified as\n"
+ " old-type,new-type.\n"
+ "--value TYPE[,TYPE] Specifies the Slice types of the database value. If the\n"
+ " type names have not changed, only one needs to be\n"
+ " specified. Otherwise, the type names are specified as\n"
+ " old-type,new-type.\n"
+ ;
+ // Note: --case-sensitive is intentionally not shown here!
+}
+
+static int
+run(int argc, char** argv, const Ice::CommunicatorPtr& communicator)
+{
+ string oldCppArgs;
+ string newCppArgs;
+ bool debug = false;
+ bool ice = true; // Needs to be true in order to create default definitions.
+ bool caseSensitive = false;
+ string outputFile;
+ bool ignoreTypeChanges = false;
+ bool purgeObjects = false;
+ bool catastrophicRecover = false;
+ bool suppress = false;
+ string inputFile;
+ vector<string> oldSlice;
+ vector<string> newSlice;
+ bool evictor = false;
+ string keyTypeNames;
+ string valueTypeNames;
+ string dbEnvName, dbName, dbEnvNameNew;
+
+ int idx = 1;
+ while(idx < argc)
+ {
+ if(strcmp(argv[idx], "-h") == 0 || strcmp(argv[idx], "--help") == 0)
+ {
+ usage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+ else if(strcmp(argv[idx], "-v") == 0 || strcmp(argv[idx], "--version") == 0)
+ {
+ cout << ICE_STRING_VERSION << endl;
+ return EXIT_SUCCESS;
+ }
+ else if(strncmp(argv[idx], "-D", 2) == 0 || strncmp(argv[idx], "-U", 2) == 0)
+ {
+ oldCppArgs += ' ';
+ oldCppArgs += argv[idx];
+ newCppArgs += ' ';
+ newCppArgs += argv[idx];
+
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "-d") == 0 || strcmp(argv[idx], "--debug") == 0)
+ {
+ debug = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "--ice") == 0)
+ {
+ ice = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "--case-sensitive") == 0)
+ {
+ caseSensitive = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "-o") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ outputFile = argv[idx + 1];
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "-i") == 0)
+ {
+ ignoreTypeChanges = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "-p") == 0)
+ {
+ purgeObjects = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "-c") == 0)
+ {
+ catastrophicRecover = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "-w") == 0)
+ {
+ suppress = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "-f") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ inputFile = argv[idx + 1];
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "--include-old") == 0)
+ {
+ oldCppArgs += " -I";
+ oldCppArgs += argv[idx + 1];
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "--include-new") == 0)
+ {
+ newCppArgs += " -I";
+ newCppArgs += argv[idx + 1];
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "--old") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ oldSlice.push_back(argv[idx + 1]);
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "--new") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ newSlice.push_back(argv[idx + 1]);
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "-e") == 0)
+ {
+ evictor = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "--key") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ keyTypeNames = argv[idx + 1];
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "--value") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ valueTypeNames = argv[idx + 1];
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(argv[idx][0] == '-')
+ {
+ cerr << argv[0] << ": unknown option `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ ++idx;
+ }
+ }
+
+ if(outputFile.empty() && argc < 4)
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ if(argc > 1)
+ {
+ dbEnvName = argv[1];
+ }
+ if(argc > 2)
+ {
+ dbName = argv[2];
+ }
+ if(argc > 3)
+ {
+ dbEnvNameNew = argv[3];
+ }
+
+ Slice::UnitPtr oldUnit = Slice::Unit::createUnit(true, true, ice, caseSensitive);
+ FreezeScript::Destroyer<Slice::UnitPtr> oldD(oldUnit);
+ if(!FreezeScript::parseSlice(argv[0], oldUnit, oldSlice, oldCppArgs, debug))
+ {
+ return EXIT_FAILURE;
+ }
+
+ Slice::UnitPtr newUnit = Slice::Unit::createUnit(true, true, ice, caseSensitive);
+ FreezeScript::Destroyer<Slice::UnitPtr> newD(newUnit);
+ if(!FreezeScript::parseSlice(argv[0], newUnit, newSlice, newCppArgs, debug))
+ {
+ return EXIT_FAILURE;
+ }
+
+ //
+ // Create the Transformer.
+ //
+ FreezeScript::Transformer transformer(communicator, oldUnit, newUnit, ignoreTypeChanges, purgeObjects);
+
+ //
+ // If no input file was provided, then we need to analyze the Slice types.
+ //
+ string descriptors;
+ if(inputFile.empty())
+ {
+ ostringstream out;
+ vector<string> missingTypes;
+ vector<string> analyzeErrors;
+
+ if(evictor)
+ {
+ transformer.analyze(out, missingTypes, analyzeErrors);
+ }
+ else
+ {
+ string oldKeyName, newKeyName, oldValueName, newValueName;
+ string::size_type pos;
+
+ if(keyTypeNames.empty() || valueTypeNames.empty())
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ pos = keyTypeNames.find(',');
+ if(pos == 0 || pos == keyTypeNames.size())
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ if(pos == string::npos)
+ {
+ oldKeyName = keyTypeNames;
+ newKeyName = keyTypeNames;
+ }
+ else
+ {
+ oldKeyName = keyTypeNames.substr(0, pos);
+ newKeyName = keyTypeNames.substr(pos + 1);
+ }
+
+ pos = valueTypeNames.find(',');
+ if(pos == 0 || pos == valueTypeNames.size())
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ if(pos == string::npos)
+ {
+ oldValueName = valueTypeNames;
+ newValueName = valueTypeNames;
+ }
+ else
+ {
+ oldValueName = valueTypeNames.substr(0, pos);
+ newValueName = valueTypeNames.substr(pos + 1);
+ }
+
+ transformer.analyze(oldKeyName, newKeyName, oldValueName, newValueName, out, missingTypes, analyzeErrors);
+ }
+
+ if(!analyzeErrors.empty())
+ {
+ for(vector<string>::const_iterator p = analyzeErrors.begin(); p != analyzeErrors.end(); ++p)
+ {
+ cerr << argv[0] << ": " << *p << endl;
+ }
+ }
+
+ if(!missingTypes.empty())
+ {
+ sort(missingTypes.begin(), missingTypes.end());
+ unique(missingTypes.begin(), missingTypes.end());
+ if(!analyzeErrors.empty())
+ {
+ cerr << endl;
+ }
+ cerr << "The following types had no matching definitions in the new Slice:" << endl;
+ for(vector<string>::const_iterator p = missingTypes.begin(); p != missingTypes.end(); ++p)
+ {
+ cerr << " " << *p << endl;
+ }
+ }
+
+ if(!analyzeErrors.empty())
+ {
+ return EXIT_FAILURE;
+ }
+
+ descriptors = out.str();
+
+ if(!outputFile.empty())
+ {
+ ofstream of(outputFile.c_str());
+ if(!of.good())
+ {
+ cerr << argv[0] << ": unable to open file `" << outputFile << "'" << endl;
+ return EXIT_FAILURE;
+ }
+ of << descriptors;
+ of.close();
+ return EXIT_SUCCESS;
+ }
+ }
+ else
+ {
+ ifstream in(inputFile.c_str());
+ char buff[1024];
+ while(true)
+ {
+ in.read(buff, 1024);
+ descriptors.append(buff, in.gcount());
+ if(in.gcount() < 1024)
+ {
+ break;
+ }
+ }
+ in.close();
+ }
+
+ if(dbEnvName == dbEnvNameNew)
+ {
+ cerr << argv[0] << ": database environment names must be different" << endl;
+ return EXIT_FAILURE;
+ }
+
+ DbEnv dbEnv(0);
+ DbEnv dbEnvNew(0);
+ DbTxn* txn = 0;
+ DbTxn* txnNew = 0;
+ Db* db = 0;
+ Db* dbNew = 0;
+ int status = EXIT_SUCCESS;
+ try
+ {
+#ifdef _WIN32
+ //
+ // Berkeley DB may use a different C++ runtime.
+ //
+ dbEnv.set_alloc(::malloc, ::realloc, ::free);
+ dbEnvNew.set_alloc(::malloc, ::realloc, ::free);
+#endif
+
+ //
+ // Open the old database environment. Use DB_RECOVER_FATAL if -c is specified.
+ //
+ {
+ u_int32_t flags = DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_CREATE;
+ if(catastrophicRecover)
+ {
+ flags |= DB_RECOVER_FATAL;
+ }
+ else
+ {
+ flags |= DB_RECOVER;
+ }
+ dbEnv.open(dbEnvName.c_str(), flags, FREEZE_SCRIPT_DB_MODE);
+ }
+
+ //
+ // Open the new database environment.
+ //
+ {
+ u_int32_t flags = DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_CREATE;
+ dbEnvNew.open(dbEnvNameNew.c_str(), flags, FREEZE_SCRIPT_DB_MODE);
+ }
+
+ //
+ // Open the old database in a transaction.
+ //
+ db = new Db(&dbEnv, 0);
+ dbEnv.txn_begin(0, &txn, 0);
+ db->open(txn, dbName.c_str(), 0, DB_BTREE, DB_RDONLY, FREEZE_SCRIPT_DB_MODE);
+
+ //
+ // Open the new database in a transaction.
+ //
+ dbNew = new Db(&dbEnvNew, 0);
+ dbEnvNew.txn_begin(0, &txnNew, 0);
+ dbNew->open(txnNew, dbName.c_str(), 0, DB_BTREE, DB_CREATE | DB_EXCL, FREEZE_SCRIPT_DB_MODE);
+
+ istringstream istr(descriptors);
+ transformer.transform(istr, db, txn, dbNew, txnNew, cerr, suppress);
+
+ //
+ // Checkpoint to migrate changes from the log to the database.
+ //
+ dbEnvNew.txn_checkpoint(0, 0, DB_FORCE);
+ }
+ catch(const DbException& ex)
+ {
+ cerr << argv[0] << ": database error: " << ex.what() << endl;
+ status = EXIT_FAILURE;
+ }
+ catch(...)
+ {
+ if(txn)
+ {
+ txn->abort();
+ }
+ if(db)
+ {
+ db->close(0);
+ delete db;
+ }
+ if(txnNew)
+ {
+ txnNew->abort();
+ }
+ if(dbNew)
+ {
+ dbNew->close(0);
+ delete dbNew;
+ }
+ dbEnv.close(0);
+ dbEnvNew.close(0);
+ throw;
+ }
+
+ if(txn)
+ {
+ txn->abort();
+ }
+ if(db)
+ {
+ db->close(0);
+ delete db;
+ }
+ if(txnNew)
+ {
+ if(status == EXIT_FAILURE)
+ {
+ txnNew->abort();
+ }
+ else
+ {
+ txnNew->commit(0);
+ }
+ }
+ if(dbNew)
+ {
+ dbNew->close(0);
+ delete dbNew;
+ }
+ dbEnv.close(0);
+ dbEnvNew.close(0);
+
+ return status;
+}
+
+int
+main(int argc, char* argv[])
+{
+ Ice::CommunicatorPtr communicator;
+ int status = EXIT_SUCCESS;
+ try
+ {
+ communicator = Ice::initialize(argc, argv);
+ status = run(argc, argv, communicator);
+ }
+ catch(const FreezeScript::Exception& ex)
+ {
+ string reason = ex.reason();
+ cerr << argv[0] << ": " << reason;
+ if(reason[reason.size() - 1] != '\n')
+ {
+ cerr << endl;
+ }
+ return EXIT_FAILURE;
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << argv[0] << ": " << ex << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(communicator)
+ {
+ communicator->destroy();
+ }
+
+ return status;
+}