From 1dc38cf49b6c7a8b661a9cc675ded94c8ab33c36 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 18 Jan 2016 07:35:12 +0200 Subject: Implement brep-migrate utility --- brep/.gitignore | 2 +- brep/buildfile | 4 +- brep/database-lock | 43 +++++ brep/database-lock.cxx | 44 +++++ brep/mod-package-search.cxx | 16 ++ brep/odb.sh | 18 +- brep/package | 6 + brep/package-extra.sql | 20 ++- brep/package.xml | 406 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 544 insertions(+), 15 deletions(-) create mode 100644 brep/database-lock create mode 100644 brep/database-lock.cxx create mode 100644 brep/package.xml (limited to 'brep') diff --git a/brep/.gitignore b/brep/.gitignore index 2c23e23..852a40d 100644 --- a/brep/.gitignore +++ b/brep/.gitignore @@ -2,4 +2,4 @@ options options.?xx package-odb* package.sql - +package-extra diff --git a/brep/buildfile b/brep/buildfile index 9826504..1aa4d08 100644 --- a/brep/buildfile +++ b/brep/buildfile @@ -10,7 +10,7 @@ define sql: file sql{*}: extension = sql sql{*}: install = data -./: lib{brep} mod{brep} sql{package} +./: lib{brep} mod{brep} sql{package package-extra} # lib{brep} # @@ -20,8 +20,10 @@ import libs += libbpkg%lib{bpkg} lib{brep}: \ {hxx cxx}{ package } \ +{file }{ package.xml } \ {hxx ixx cxx}{ package-odb } \ {hxx cxx}{ package-traits } \ +{hxx cxx}{ database-lock } \ {hxx }{ types } \ {hxx }{ utility } \ {hxx }{ version } \ diff --git a/brep/database-lock b/brep/database-lock new file mode 100644 index 0000000..72036a1 --- /dev/null +++ b/brep/database-lock @@ -0,0 +1,43 @@ +// file : brep/database-lock -*- C++ -*- +// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BREP_DATABASE_LOCK +#define BREP_DATABASE_LOCK + +#include // unique_ptr +#include + +#include // database, transaction +#include + +namespace brep +{ + struct database_locked: std::exception + { + virtual char const* + what () const throw () {return "database locked";} + }; + + // Try to "lock" the PostgreSQL database in the constructor and release the + // lock in the destructor. Throw database_locked if the database is already + // locked by someone else. May also throw odb::pgsql::database_exception. + // + // This mechanism is used by the brep loader and schema migration tool to + // make sure they don't step on each others toes. + // + // Note: movable but not copyable. + // + class database_lock + { + public: + explicit + database_lock (odb::pgsql::database&); + + private: + odb::pgsql::connection_ptr connection_; + std::unique_ptr transaction_; + }; +} + +#endif // BREP_DATABASE_LOCK diff --git a/brep/database-lock.cxx b/brep/database-lock.cxx new file mode 100644 index 0000000..3b8ae21 --- /dev/null +++ b/brep/database-lock.cxx @@ -0,0 +1,44 @@ +// file : brep/database-lock.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include +#include +#include + +namespace brep +{ + using namespace odb::pgsql; + + database_lock:: + database_lock (database& db) + { + // Before locking the table make sure it exists. + // + { + transaction t (db.begin ()); + db.execute ("CREATE TABLE IF NOT EXISTS database_mutex ()"); + t.commit (); + } + + connection_ = db.connection (); + + // Don't make current. Will be rolled back in destructor. + // + transaction_.reset (new transaction (connection_->begin (), false)); + + try + { + connection_->execute ("LOCK TABLE database_mutex NOWAIT"); + } + catch (const database_exception& e) + { + if (e.sqlstate () == "55P03") // The table is already locked. + throw database_locked (); + + throw; + } + } +} diff --git a/brep/mod-package-search.cxx b/brep/mod-package-search.cxx index 4326435..d649ff4 100644 --- a/brep/mod-package-search.cxx +++ b/brep/mod-package-search.cxx @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ #include #include +#include #include #include @@ -38,6 +40,20 @@ init (scanner& s) options_->root (dir_path ("/")); db_ = shared_database (*options_); + + // Check that the database schema matches the current one. It's enough to + // perform the check in just a single module implementation (and we don't + // do in the dispatcher because it doesn't use the database). + // + // Note that the failure can be reported by each web server worker process. + // While it could be tempting to move the check to the + // repository_root::version() function, it would be wrong. The function can + // be called by a different process (usually the web server root one) not + // having the proper permissions to access the database. + // + if (schema_catalog::current_version (*db_) != db_->schema_version ()) + fail << "database schema differs from the current one (module " + << BREP_VERSION_STR << ")"; } template diff --git a/brep/odb.sh b/brep/odb.sh index 489d423..d68b28f 100755 --- a/brep/odb.sh +++ b/brep/odb.sh @@ -1,11 +1,13 @@ #! /usr/bin/env bash odb -d pgsql --std c++11 --generate-query --generate-schema \ - --odb-epilogue '#include ' \ - --hxx-prologue '#include ' \ - --hxx-prologue "#include " \ - --sql-epilogue-file package-extra.sql \ - -I .. -I ../../libbpkg -I ../../libbutl \ - --hxx-suffix "" --include-with-brackets \ - --include-prefix brep --guard-prefix BREP \ - package + --schema-format sql --schema-format embedded \ + --odb-epilogue '#include ' \ + --hxx-prologue '#include ' \ + --hxx-prologue '#include ' \ + -I .. -I ../../libbpkg -I ../../libbutl \ + --hxx-suffix "" --include-with-brackets \ + --include-prefix brep --guard-prefix BREP \ + package + +xxd -i package-extra diff --git a/brep/package b/brep/package index 92a2320..2700e8a 100644 --- a/brep/package +++ b/brep/package @@ -19,6 +19,12 @@ #include #include +// Used by the data migration entries. +// +#define LIBBREP_SCHEMA_VERSION_BASE 1 + +#pragma db model version(LIBBREP_SCHEMA_VERSION_BASE, 1, open) + // The uint16_t value range is not fully covered by SMALLINT PostgreSQL type // to which uint16_t is mapped by default. // diff --git a/brep/package-extra.sql b/brep/package-extra.sql index dc37d1f..9a847e3 100644 --- a/brep/package-extra.sql +++ b/brep/package-extra.sql @@ -1,12 +1,22 @@ -DROP TYPE IF EXISTS weighted_text CASCADE; -CREATE TYPE weighted_text AS (a TEXT, b TEXT, c TEXT, d TEXT); - +-- This file should be parsable by the brep-migrate utility. To decrease the +-- parser complexity, the following restrictions are placed: +-- +-- * comments must start with -- at the beginning of the line (ignoring +-- leading spaces) +-- * only CREATE and DROP statements for FUNCTION and TYPE +-- * function bodies must be defined using $$-quoted strings +-- * strings other then function bodies must be quoted with ' or " +-- * statements must end with ";\n" +-- DROP FUNCTION IF EXISTS to_tsvector(IN document weighted_text); DROP FUNCTION IF EXISTS search_packages(IN query tsquery, INOUT name TEXT); DROP FUNCTION IF EXISTS search_latest_packages(IN query tsquery); DROP FUNCTION IF EXISTS latest_package(INOUT name TEXT); DROP FUNCTION IF EXISTS latest_packages(); +DROP TYPE IF EXISTS weighted_text CASCADE; +CREATE TYPE weighted_text AS (a TEXT, b TEXT, c TEXT, d TEXT); + -- Return the latest versions of internal packages as a set of package rows. -- CREATE FUNCTION @@ -72,9 +82,9 @@ $$ LANGUAGE SQL STABLE; -- Search for packages matching the search query and having the specified name. -- Return a set of rows containing the package id and search rank. If query -- is NULL, then match all packages and return 0 rank for all rows. --- +-- CREATE FUNCTION -search_packages(IN query tsquery, +search_packages(IN query tsquery, INOUT name TEXT, OUT version_epoch INTEGER, OUT version_canonical_upstream TEXT, diff --git a/brep/package.xml b/brep/package.xml new file mode 100644 index 0000000..9c88f25 --- /dev/null +++ b/brep/package.xml @@ -0,0 +1,406 @@ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
-- cgit v1.1