aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2024-11-20 15:17:26 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2024-12-10 16:44:55 +0200
commit475771f84d3fb6197fea772d67e5a59c46b512e5 (patch)
treed3a80f655cb0261d5cfd5728a5159e064050320c
parent40a3855e2341529624050b4324e73e774967111a (diff)
Add support for tenant service reference count
-rw-r--r--libbrep/build-extra.sql1
-rw-r--r--libbrep/build.hxx2
-rw-r--r--libbrep/build.xml2
-rw-r--r--libbrep/common.hxx7
-rw-r--r--libbrep/package.hxx2
-rw-r--r--libbrep/package.xml6
-rw-r--r--migrate/migrate.cxx10
-rw-r--r--mod/ci-common.cxx64
-rw-r--r--mod/ci-common.hxx12
-rw-r--r--mod/mod-ci-github.cxx2
10 files changed, 88 insertions, 20 deletions
diff --git a/libbrep/build-extra.sql b/libbrep/build-extra.sql
index 0c0f010..3134fbb 100644
--- a/libbrep/build-extra.sql
+++ b/libbrep/build-extra.sql
@@ -50,6 +50,7 @@ CREATE FOREIGN TABLE build_tenant (
archived BOOLEAN NOT NULL,
service_id TEXT NULL,
service_type TEXT NULL,
+ service_ref_count BIGINT NULL,
service_data TEXT NULL,
unloaded_timestamp BIGINT NULL,
unloaded_notify_interval BIGINT NULL,
diff --git a/libbrep/build.hxx b/libbrep/build.hxx
index b485636..5ebbb0c 100644
--- a/libbrep/build.hxx
+++ b/libbrep/build.hxx
@@ -28,7 +28,7 @@
//
#define LIBBREP_BUILD_SCHEMA_VERSION_BASE 28
-#pragma db model version(LIBBREP_BUILD_SCHEMA_VERSION_BASE, 28, closed)
+#pragma db model version(LIBBREP_BUILD_SCHEMA_VERSION_BASE, 29, 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
diff --git a/libbrep/build.xml b/libbrep/build.xml
index d58e5f4..284db49 100644
--- a/libbrep/build.xml
+++ b/libbrep/build.xml
@@ -1,4 +1,6 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" schema-name="build" version="1">
+ <changeset version="29"/>
+
<model version="28">
<table name="build" kind="object">
<column name="package_tenant" type="TEXT" null="false"/>
diff --git a/libbrep/common.hxx b/libbrep/common.hxx
index d2009f5..22302f3 100644
--- a/libbrep/common.hxx
+++ b/libbrep/common.hxx
@@ -543,17 +543,22 @@ namespace brep
//
// Note that the {id, type} pair must be unique.
//
+ // The reference count is used to keep track of the number of attempts to
+ // create a duplicate tenant with this {id, type} (see ci_start::create()
+ // for details).
+ //
#pragma db value
struct tenant_service
{
string id;
string type;
+ uint64_t ref_count;
optional<string> data;
tenant_service () = default;
tenant_service (string i, string t, optional<string> d = nullopt)
- : id (move (i)), type (move (t)), data (move (d)) {}
+ : id (move (i)), type (move (t)), ref_count (1), data (move (d)) {}
};
// Version comparison operators.
diff --git a/libbrep/package.hxx b/libbrep/package.hxx
index 79b2c68..2714d10 100644
--- a/libbrep/package.hxx
+++ b/libbrep/package.hxx
@@ -20,7 +20,7 @@
//
#define LIBBREP_PACKAGE_SCHEMA_VERSION_BASE 34
-#pragma db model version(LIBBREP_PACKAGE_SCHEMA_VERSION_BASE, 35, closed)
+#pragma db model version(LIBBREP_PACKAGE_SCHEMA_VERSION_BASE, 36, closed)
namespace brep
{
diff --git a/libbrep/package.xml b/libbrep/package.xml
index 8b6c706..ac48ec4 100644
--- a/libbrep/package.xml
+++ b/libbrep/package.xml
@@ -1,4 +1,10 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" schema-name="package" version="1">
+ <changeset version="36">
+ <alter-table name="tenant">
+ <add-column name="service_ref_count" type="BIGINT" null="true"/>
+ </alter-table>
+ </changeset>
+
<changeset version="35">
<alter-table name="package">
<add-column name="reviews_pass" type="BIGINT" null="true"/>
diff --git a/migrate/migrate.cxx b/migrate/migrate.cxx
index 090fcac..095e6a3 100644
--- a/migrate/migrate.cxx
+++ b/migrate/migrate.cxx
@@ -208,7 +208,6 @@ create (database& db, bool extra_only) const
// Register the data migration functions for the package database schema.
//
-#if 0
template <schema_version v>
using package_migration_entry_base =
data_migration_entry<v, LIBBREP_PACKAGE_SCHEMA_VERSION_BASE>;
@@ -220,11 +219,14 @@ struct package_migration_entry: package_migration_entry_base<v>
: package_migration_entry_base<v> (f, "package") {}
};
-static const package_migration_entry<26>
-package_migrate_v26 ([] (database& db)
+static const package_migration_entry<36>
+package_migrate_v36 ([] (database& db)
{
+ // Set the reference count to 1 for tenant associated services.
+ //
+ db.execute ("UPDATE tenant SET service_ref_count = 1 "
+ "WHERE service_id IS NOT NULL");
});
-#endif
// Register the data migration functions for the build database schema.
//
diff --git a/mod/ci-common.cxx b/mod/ci-common.cxx
index 4b9f9f9..cba421b 100644
--- a/mod/ci-common.cxx
+++ b/mod/ci-common.cxx
@@ -553,7 +553,11 @@ namespace brep
assert (!transaction::has_current ());
build_tenant t;
+
+ // Set the reference count to 1 for the `created` result.
+ //
duplicate_tenant_result r (duplicate_tenant_result::created);
+ service.ref_count = 1;
for (string request_id;;)
{
@@ -584,14 +588,31 @@ namespace brep
: duplicate_tenant_mode::ignore);
}
+ // Shouldn't be here otherwise.
+ //
+ assert (t->service);
+
// Bail out in the ignore mode and cancel the tenant in the
// replace mode.
//
if (mode == duplicate_tenant_mode::ignore)
+ {
+ // Increment the reference count for the `ignored` result.
+ //
+ ++(t->service->ref_count);
+
+ db.update (t);
+ tr.commit ();
+
return make_pair (move (t->id), duplicate_tenant_result::ignored);
+ }
assert (mode == duplicate_tenant_mode::replace);
+ // Preserve the current reference count for the `replaced` result.
+ //
+ service.ref_count = t->service->ref_count;
+
if (t->unloaded_timestamp)
{
db.erase (t);
@@ -678,6 +699,7 @@ namespace brep
//
request_id = move (t.id);
service = move (*t.service);
+ service.ref_count = 1;
r = duplicate_tenant_result::created;
}
}
@@ -788,7 +810,8 @@ namespace brep
odb::core::database& db,
size_t retry,
const string& type,
- const string& id) const
+ const string& id,
+ bool ref_count) const
{
using namespace odb::core;
@@ -810,25 +833,44 @@ namespace brep
if (t == nullptr)
return nullopt;
- r = move (t->service);
+ // Shouldn't be here otherwise.
+ //
+ assert (t->service && t->service->ref_count != 0);
- if (t->unloaded_timestamp)
+ bool cancel (!ref_count || --(t->service->ref_count) == 0);
+
+ if (cancel)
{
- db.erase (t);
+ // Move out the service state before it is dropped from the tenant.
+ //
+ r = move (t->service);
+
+ if (t->unloaded_timestamp)
+ {
+ db.erase (t);
+ }
+ else
+ {
+ t->service = nullopt;
+ t->archived = true;
+ db.update (t);
+ }
+
+ if (trace != nullptr)
+ *trace << "CI request " << t->id << " for service " << id << ' '
+ << type << " is canceled";
}
else
{
- t->service = nullopt;
- t->archived = true;
- db.update (t);
+ db.update (t); // Update the service reference count.
+
+ // Move out the service state after the tenant is updated.
+ //
+ r = move (t->service);
}
tr.commit ();
- if (trace != nullptr)
- *trace << "CI request " << t->id << " for service " << id << ' '
- << type << " is canceled";
-
// Bail out if we have successfully updated or erased the tenant
// object.
//
diff --git a/mod/ci-common.hxx b/mod/ci-common.hxx
index 36d5f0e..b32d397 100644
--- a/mod/ci-common.hxx
+++ b/mod/ci-common.hxx
@@ -103,6 +103,10 @@ namespace brep
// Finally note that only duplicate_tenant_mode::fail can be used if the
// service id is empty.
//
+ // The tenant reference count is set to 1 if the result is `created`,
+ // incremented if the result is `ignored`, and preserved if the result is
+ // `replaced`.
+ //
// Repeat the attempts on the recoverable database failures (deadlocks,
// etc) and throw runtime_error if no more retries left.
//
@@ -150,6 +154,11 @@ namespace brep
// dropped. Note that the latter allow using unloaded tenants as a
// relatively cheap asynchronous execution mechanism.
//
+ // If ref_count is true, then decrement the tenant reference count and
+ // only cancel the CI request if it becomes 0. In this mode the caller can
+ // determine if the request was actually canceled by checking if the
+ // reference count in the returned service state is 0.
+ //
// Repeat the attempts on the recoverable database failures (deadlocks,
// etc) and throw runtime_error if no more retries left.
//
@@ -162,7 +171,8 @@ namespace brep
odb::core::database&,
size_t retry,
const string& type,
- const string& id) const;
+ const string& id,
+ bool ref_count = false) const;
// Cancel previously created or started CI request. Return false if there
// is no tenant for the specified tenant id. Note that the reason argument
diff --git a/mod/mod-ci-github.cxx b/mod/mod-ci-github.cxx
index 9d2606b..ba80ed6 100644
--- a/mod/mod-ci-github.cxx
+++ b/mod/mod-ci-github.cxx
@@ -828,7 +828,7 @@ namespace brep
if (system_clock::now () > sd.installation_access.expires_at)
{
- if (new_iat = get_iat ())
+ if ((new_iat = get_iat ()))
iat = &*new_iat;
else
throw server_error ();