aboutsummaryrefslogtreecommitdiff
path: root/libbrep/build.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbrep/build.hxx')
-rw-r--r--libbrep/build.hxx355
1 files changed, 300 insertions, 55 deletions
diff --git a/libbrep/build.hxx b/libbrep/build.hxx
index fc9f675..af49c03 100644
--- a/libbrep/build.hxx
+++ b/libbrep/build.hxx
@@ -1,5 +1,4 @@
// file : libbrep/build.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_BUILD_HXX
@@ -10,28 +9,30 @@
#include <odb/core.hxx>
#include <odb/section.hxx>
-#include <libbutl/target-triplet.mxx>
-
-#include <libbbot/manifest.hxx>
-
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-// Must be included last (see assert in libbrep/common.hxx).
-//
#include <libbrep/common.hxx>
#include <libbrep/build-package.hxx>
+// Must be included after libbrep/common.hxx, so that the _version structure
+// get defined before libbpkg/manifest.hxx inclusion.
+//
+// Note that if we start using assert() in get/set expressions in this header,
+// we will have to redefine it for ODB compiler after all include directives
+// (see libbrep/common.hxx for details).
+//
+#include <libbbot/manifest.hxx>
+
// Used by the data migration entries.
//
-#define LIBBREP_BUILD_SCHEMA_VERSION_BASE 9
+#define LIBBREP_BUILD_SCHEMA_VERSION_BASE 20
-#pragma db model version(LIBBREP_BUILD_SCHEMA_VERSION_BASE, 9, closed)
+#pragma db model version(LIBBREP_BUILD_SCHEMA_VERSION_BASE, 27, closed)
-// We have to keep these mappings at the global scope instead of inside
-// the brep namespace because they need to be also effective in the
-// bbot namespace from which we "borrow" types (and some of them use the mapped
-// types).
+// We have to keep these mappings at the global scope instead of inside the
+// brep namespace because they need to be also effective in the bbot namespace
+// from which we "borrow" types (and some of them use the mapped types).
//
#pragma db map type(bbot::result_status) as(std::string) \
to(to_string (?)) \
@@ -43,14 +44,23 @@ namespace brep
struct build_id
{
package_id package;
- string configuration;
+ target_triplet target;
+ string target_config_name;
+ string package_config_name;
string toolchain_name;
canonical_version toolchain_version;
build_id () = default;
- build_id (package_id p, string c, string n, const brep::version& v)
+ build_id (package_id p,
+ target_triplet t,
+ string tc,
+ string pc,
+ string n,
+ const brep::version& v)
: package (move (p)),
- configuration (move (c)),
+ target (move (t)),
+ target_config_name (move (tc)),
+ package_config_name (move (pc)),
toolchain_name (move (n)),
toolchain_version (v) {}
};
@@ -61,7 +71,13 @@ namespace brep
if (x.package != y.package)
return x.package < y.package;
- if (int r = x.configuration.compare (y.configuration))
+ if (int r = x.target.compare (y.target))
+ return r < 0;
+
+ if (int r = x.target_config_name.compare (y.target_config_name))
+ return r < 0;
+
+ if (int r = x.package_config_name.compare (y.package_config_name))
return r < 0;
if (int r = x.toolchain_name.compare (y.toolchain_name))
@@ -70,7 +86,7 @@ namespace brep
return compare_version_lt (x.toolchain_version, y.toolchain_version, true);
}
- // These allow comparing objects that have package, configuration,
+ // These allow comparing objects that have package, configuration, target,
// toolchain_name, and toolchain_version data members to build_id values.
// The idea is that this works for both query members of build id types as
// well as for values of the build_id type.
@@ -78,35 +94,84 @@ namespace brep
template <typename T>
inline auto
operator== (const T& x, const build_id& y)
- -> decltype (x.package == y.package &&
- x.configuration == y.configuration &&
- x.toolchain_name == y.toolchain_name &&
+ -> decltype (x.package == y.package &&
+ x.target == y.target &&
+ x.target_config_name == y.target_config_name &&
+ x.package_config_name == y.package_config_name &&
+ x.toolchain_name == y.toolchain_name &&
x.toolchain_version.epoch == y.toolchain_version.epoch)
{
- return x.package == y.package &&
- x.configuration == y.configuration &&
- x.toolchain_name == y.toolchain_name &&
+ return x.package == y.package &&
+ x.target == y.target &&
+ x.target_config_name == y.target_config_name &&
+ x.package_config_name == y.package_config_name &&
+ x.toolchain_name == y.toolchain_name &&
compare_version_eq (x.toolchain_version, y.toolchain_version, true);
}
template <typename T>
inline auto
operator!= (const T& x, const build_id& y)
- -> decltype (x.package == y.package &&
- x.configuration == y.configuration &&
- x.toolchain_name == y.toolchain_name &&
+ -> decltype (x.package == y.package &&
+ x.target == y.target &&
+ x.target_config_name == y.target_config_name &&
+ x.package_config_name == y.package_config_name &&
+ x.toolchain_name == y.toolchain_name &&
x.toolchain_version.epoch == y.toolchain_version.epoch)
{
- return x.package != y.package ||
- x.configuration != y.configuration ||
- x.toolchain_name != y.toolchain_name ||
+ return x.package != y.package ||
+ x.target != y.target ||
+ x.target_config_name != y.target_config_name ||
+ x.package_config_name != y.package_config_name ||
+ x.toolchain_name != y.toolchain_name ||
compare_version_ne (x.toolchain_version, y.toolchain_version, true);
}
+ // Allow comparing the query members with the query parameters bound by
+ // reference to variables of the build id type (in particular in the
+ // prepared queries).
+ //
+ // Note that it is not operator==() since the query template parameter type
+ // can not be deduced from the function parameter types and needs to be
+ // specified explicitly.
+ //
+ template <typename T, typename ID>
+ inline auto
+ equal (const ID& x, const build_id& y, bool toolchain_version = true)
+ -> decltype (x.package.tenant == odb::query<T>::_ref (y.package.tenant) &&
+ x.package.name == odb::query<T>::_ref (y.package.name) &&
+ x.package.version.epoch ==
+ odb::query<T>::_ref (y.package.version.epoch) &&
+ x.target_config_name ==
+ odb::query<T>::_ref (y.target_config_name) &&
+ x.toolchain_name == odb::query<T>::_ref (y.toolchain_name) &&
+ x.toolchain_version.epoch ==
+ odb::query<T>::_ref (y.toolchain_version.epoch))
+ {
+ using query = odb::query<T>;
+
+ query r (equal<T> (x.package, y.package) &&
+ x.target == query::_ref (y.target) &&
+ x.target_config_name == query::_ref (y.target_config_name) &&
+ x.package_config_name == query::_ref (y.package_config_name) &&
+ x.toolchain_name == query::_ref (y.toolchain_name));
+
+ if (toolchain_version)
+ r = r && equal<T> (x.toolchain_version, y.toolchain_version);
+
+ return r;
+ }
+
// build_state
//
+ // The queued build state is semantically equivalent to a non-existent
+ // build. It is only used for those tenants, which have a third-party
+ // service associated that requires the `queued` notifications (see
+ // mod/tenant-service.hxx for background).
+ //
enum class build_state: std::uint8_t
{
+ queued,
building,
built
};
@@ -158,12 +223,6 @@ namespace brep
? bbot::to_result_status (*(?)) \
: brep::optional_result_status ())
- // target_triplet
- //
- #pragma db map type(butl::target_triplet) as(string) \
- to((?).string ()) \
- from(butl::target_triplet (?))
-
// operation_results
//
using bbot::operation_result;
@@ -171,6 +230,13 @@ namespace brep
using bbot::operation_results;
+ #pragma db value
+ struct build_machine
+ {
+ string name;
+ string summary;
+ };
+
#pragma db object pointer(shared_ptr) session
class build
{
@@ -179,29 +245,72 @@ namespace brep
using package_name_type = brep::package_name;
// Create the build object with the building state, non-existent status,
- // the timestamp set to now and the force state set to unforced.
+ // the timestamp set to now, and the force state set to unforced.
//
build (string tenant,
- package_name_type,
- version,
- string configuration,
+ package_name_type, version,
+ target_triplet,
+ string target_config_name,
+ string package_config_name,
string toolchain_name, version toolchain_version,
+ optional<string> interactive,
optional<string> agent_fingerprint,
optional<string> agent_challenge,
- string machine, string machine_summary,
- butl::target_triplet);
+ build_machine,
+ vector<build_machine> auxiliary_machines,
+ string controller_checksum,
+ string machine_checksum);
+
+ // Create the build object with the queued state.
+ //
+ build (string tenant,
+ package_name_type, version,
+ target_triplet,
+ string target_config_name,
+ string package_config_name,
+ string toolchain_name, version toolchain_version);
+
+ // Create the build object with the built state, the specified status and
+ // operation results, all the timestamps set to now, and the force state
+ // set to unforced.
+ //
+ build (string tenant,
+ package_name_type, version,
+ target_triplet,
+ string target_config_name,
+ string package_config_name,
+ string toolchain_name, version toolchain_version,
+ result_status,
+ operation_results,
+ build_machine,
+ vector<build_machine> auxiliary_machines = {});
+
+ // Move-only type.
+ //
+ build (build&&);
+ build& operator= (build&&);
+
+ build (const build&) = delete;
+ build& operator= (const build&) = delete;
build_id id;
string& tenant; // Tracks id.package.tenant.
package_name_type& package_name; // Tracks id.package.name.
upstream_version package_version; // Original of id.package.version.
- string& configuration; // Tracks id.configuration.
+ target_triplet& target; // Tracks id.target.
+ string& target_config_name; // Tracks id.target_config_name.
+ string& package_config_name; // Tracks id.package_config_name.
string& toolchain_name; // Tracks id.toolchain_name.
upstream_version toolchain_version; // Original of id.toolchain_version.
build_state state;
+ // If present, the login information for the interactive build. May be
+ // present only in the building state.
+ //
+ optional<string> interactive;
+
// Time of the last state change (the creation time initially).
//
timestamp_type timestamp;
@@ -213,14 +322,35 @@ namespace brep
//
optional<result_status> status;
+ // Times of the last soft/hard completed (re)builds. Used to decide when
+ // to perform soft and hard rebuilds, respectively.
+ //
+ // The soft timestamp is updated whenever we receive a task result.
+ //
+ // The hard timestamp is updated whenever we receive a task result with
+ // a status other than skip.
+ //
+ // Also note that whenever hard_timestamp is updated, soft_timestamp is
+ // updated as well and whenever soft_timestamp is updated, timestamp is
+ // updated as well. Thus the following condition is always true:
+ //
+ // hard_timestamp <= soft_timestamp <= timestamp
+ //
+ // Note that the "completed" above means that we may analyze the task
+ // result/log and deem it as not completed and proceed with automatic
+ // rebuild (the flake monitor idea).
+ //
+ timestamp_type soft_timestamp;
+ timestamp_type hard_timestamp;
+
// May be present only for the building state.
//
optional<string> agent_fingerprint;
optional<string> agent_challenge;
- string machine;
- string machine_summary;
- butl::target_triplet target;
+ build_machine machine;
+ vector<build_machine> auxiliary_machines;
+ odb::section auxiliary_machines_section;
// Note that the logs are stored as std::string/TEXT which is Ok since
// they are UTF-8 and our database is UTF-8.
@@ -228,6 +358,21 @@ namespace brep
operation_results results;
odb::section results_section;
+ // Checksums of entities involved in the build.
+ //
+ // Optional checksums are provided by the external entities (agent and
+ // worker). All are absent initially.
+ //
+ // Note that the agent checksum can also be absent after the hard rebuild
+ // task is issued and the worker and dependency checksums - after a failed
+ // rebuild (error result status or worse).
+ //
+ string controller_checksum;
+ string machine_checksum;
+ optional<string> agent_checksum;
+ optional<string> worker_checksum;
+ optional<string> dependency_checksum;
+
// Database mapping.
//
#pragma db member(id) id column("")
@@ -236,7 +381,9 @@ namespace brep
#pragma db member(package_name) transient
#pragma db member(package_version) \
set(this.package_version.init (this.id.package.version, (?)))
- #pragma db member(configuration) transient
+ #pragma db member(target) transient
+ #pragma db member(target_config_name) transient
+ #pragma db member(package_config_name) transient
#pragma db member(toolchain_name) transient
#pragma db member(toolchain_version) \
set(this.toolchain_version.init (this.id.toolchain_version, (?)))
@@ -245,24 +392,34 @@ namespace brep
//
#pragma db member(timestamp) index
+ #pragma db member(machine) transient
+
+ #pragma db member(machine_name) virtual(std::string) \
+ access(machine.name) column("machine")
+
+ #pragma db member(machine_summary) virtual(std::string) \
+ access(machine.summary)
+
+ #pragma db member(auxiliary_machines) id_column("") value_column("") \
+ section(auxiliary_machines_section)
+
+ #pragma db member(auxiliary_machines_section) load(lazy) update(always)
+
#pragma db member(results) id_column("") value_column("") \
section(results_section)
#pragma db member(results_section) load(lazy) update(always)
- build (const build&) = delete;
- build& operator= (const build&) = delete;
-
private:
friend class odb::access;
build ()
: tenant (id.package.tenant),
package_name (id.package.name),
- configuration (id.configuration),
- toolchain_name (id.toolchain_name)
- {
- }
+ target (id.target),
+ target_config_name (id.target_config_name),
+ package_config_name (id.package_config_name),
+ toolchain_name (id.toolchain_name) {}
};
// Note that ADL can't find the equal operator in join conditions, so we use
@@ -312,7 +469,7 @@ namespace brep
canonical_version version_;
};
- // Build of an existing buildable package.
+ // Builds of existing buildable packages.
//
#pragma db view \
object(build) \
@@ -323,6 +480,7 @@ namespace brep
struct package_build
{
shared_ptr<brep::build> build;
+ bool archived; // True if the tenant the build belongs to is archived.
};
#pragma db view \
@@ -341,6 +499,93 @@ namespace brep
//
#pragma db member(result) column("count(" + build::id.package.name + ")")
};
+
+ // Ids of existing buildable package builds.
+ //
+ #pragma db view object(build) \
+ object(build_package inner: \
+ brep::operator== (build::id.package, build_package::id) && \
+ build_package::buildable)
+ struct package_build_id
+ {
+ build_id id;
+
+ operator build_id& () {return id;}
+ };
+
+ // Used to track the package build delays since the last build or, if not
+ // present, since the first opportunity to build the package.
+ //
+ #pragma db object pointer(shared_ptr) session
+ class build_delay
+ {
+ public:
+ using package_name_type = brep::package_name;
+
+ // If toolchain version is empty, then the object represents a minimum
+ // delay across all versions of the toolchain.
+ //
+ build_delay (string tenant,
+ package_name_type, version,
+ target_triplet,
+ string target_config_name,
+ string package_config_name,
+ string toolchain_name, version toolchain_version,
+ timestamp package_timestamp);
+
+ build_id id;
+
+ string& tenant; // Tracks id.package.tenant.
+ package_name_type& package_name; // Tracks id.package.name.
+ upstream_version package_version; // Original of id.package.version.
+ target_triplet& target; // Tracks id.target.
+ string& target_config_name; // Tracks id.target_config_name.
+ string& package_config_name; // Tracks id.package_config_name.
+ string& toolchain_name; // Tracks id.toolchain_name.
+ upstream_version toolchain_version; // Original of id.toolchain_version.
+
+ // Times of the latest soft and hard rebuild delay reports. Initialized
+ // with timestamp_nonexistent by default.
+ //
+ // Note that both reports notify about initial build delays (at their
+ // respective time intervals).
+ //
+ timestamp report_soft_timestamp;
+ timestamp report_hard_timestamp;
+
+ // Time when the package is initially considered as buildable for this
+ // configuration and toolchain. It is used to track the build delay if the
+ // build object is absent (the first build task is not yet issued, the
+ // build is removed by brep-clean, etc).
+ //
+ timestamp package_timestamp;
+
+ // Database mapping.
+ //
+ #pragma db member(id) id column("")
+
+ #pragma db member(tenant) transient
+ #pragma db member(package_name) transient
+ #pragma db member(package_version) \
+ set(this.package_version.init (this.id.package.version, (?)))
+ #pragma db member(target) transient
+ #pragma db member(target_config_name) transient
+ #pragma db member(package_config_name) transient
+ #pragma db member(toolchain_name) transient
+ #pragma db member(toolchain_version) \
+ set(this.toolchain_version.init (this.id.toolchain_version, (?)))
+
+ private:
+ friend class odb::access;
+
+ build_delay ()
+ : tenant (id.package.tenant),
+ package_name (id.package.name),
+ target (id.target),
+ target_config_name (id.target_config_name),
+ package_config_name (id.package_config_name),
+ toolchain_name (id.toolchain_name) {}
+ };
}
#endif // LIBBREP_BUILD_HXX