diff --git a/assets/sai.js b/assets/sai.js
index 74a06f7..ee428f5 100644
--- a/assets/sai.js
+++ b/assets/sai.js
@@ -1920,6 +1920,18 @@ window.addEventListener("load", function() {
}
];
+ if (taskDiv.classList.contains("taskstate4") ||
+ taskDiv.classList.contains("taskstate6"))
+ menuItems.splice(1, 0, {
+ label: "Rebuild last step",
+ callback: () => {
+ sai.send(JSON.stringify({
+ schema: "com.warmcat.sai.taskrebuildlaststep",
+ uuid: taskUuid
+ }));
+ }
+ });
+
createContextMenu(event, menuItems);
}
});
diff --git a/src/builder/b-metrics.c b/src/builder/b-metrics.c
index 5532cfb..c2164b4 100644
--- a/src/builder/b-metrics.c
+++ b/src/builder/b-metrics.c
@@ -68,22 +68,6 @@ saib_get_free_ram_kib(void)
statex.dwLength = sizeof(statex);
GlobalMemoryStatusEx(&statex);
return (unsigned int)(statex.ullAvailPhys / 1024);
-#elif defined(__APPLE__)
- int mib[2];
- size_t len;
- uint64_t total_mem;
-
- mib[0] = CTL_HW;
- mib[1] = HW_MEMSIZE;
- len = sizeof(total_mem);
- sysctl(mib, 2, &total_mem, &len, NULL, 0);
-
- return (unsigned int)(total_mem / 1024);
-#elif defined(_WIN32)
- MEMORYSTATUSEX statex;
- statex.dwLength = sizeof(statex);
- GlobalMemoryStatusEx(&statex);
- return (unsigned int)(statex.ullTotalPhys / 1024);
#else
return 0;
#endif
@@ -108,6 +92,22 @@ saib_get_total_ram_kib(void)
fclose(f);
return total_kib;
+#elif defined(__APPLE__)
+ int mib[2];
+ size_t len;
+ uint64_t total_mem;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_MEMSIZE;
+ len = sizeof(total_mem);
+ sysctl(mib, 2, &total_mem, &len, NULL, 0);
+
+ return (unsigned int)(total_mem / 1024);
+#elif defined(_WIN32)
+ MEMORYSTATUSEX statex;
+ statex.dwLength = sizeof(statex);
+ GlobalMemoryStatusEx(&statex);
+ return (unsigned int)(statex.ullTotalPhys / 1024);
#else
return 0;
#endif
diff --git a/src/server/s-private.h b/src/server/s-private.h
index 5387e95..57d6b9c 100644
--- a/src/server/s-private.h
+++ b/src/server/s-private.h
@@ -289,6 +289,8 @@ sais_activity_cb(lws_sorted_usec_list_t *sul);
sai_db_result_t
sais_task_reset(struct vhd *vhd, const char *task_uuid, int from_rejection);
+sai_db_result_t
+sais_task_rebuild_last_step(struct vhd *vhd, const char *task_uuid);
int
sais_task_cancel(struct vhd *vhd, const char *task_uuid);
diff --git a/src/server/s-task.c b/src/server/s-task.c
index 383db95..3257566 100644
--- a/src/server/s-task.c
+++ b/src/server/s-task.c
@@ -83,6 +83,7 @@ sais_set_task_state(struct vhd *vhd, const char *builder_name,
lws_dll2_owner_t o;
int n, task_ostate;
int ostate = state;
+ uint64_t started_orig = started;
if (state == SAIES_STEP_SUCCESS)
state = SAIES_BEING_BUILT;
@@ -171,7 +172,8 @@ sais_set_task_state(struct vhd *vhd, const char *builder_name,
builder_name ? ",builder_name='" : "",
builder_name ? esc : "",
builder_name ? "'" : "",
- esc3, esc4, state == SAIES_WAITING ? ",build_step=0" : "",
+ esc3, esc4, state == SAIES_WAITING && started_orig == 1 ?
+ ",build_step=0" : "",
esc2);
if (sqlite3_exec((sqlite3 *)e->pdb, update, NULL, NULL, NULL) != SQLITE_OK) {
@@ -911,6 +913,78 @@ sais_task_reset(struct vhd *vhd, const char *task_uuid, int from_rejection)
return SAI_DB_RESULT_OK;
}
+sai_db_result_t
+sais_task_rebuild_last_step(struct vhd *vhd, const char *task_uuid)
+{
+ char esc[96], cmd[256], event_uuid[33];
+ sqlite3 *pdb = NULL;
+ lws_dll2_owner_t o;
+ struct lwsac *ac = NULL;
+ sai_task_t *task;
+ int ret;
+
+ if (!task_uuid[0])
+ return SAI_DB_RESULT_OK;
+
+ lwsl_notice("%s: received request to rebuild last step of task %s\n",
+ __func__, task_uuid);
+
+ sai_task_uuid_to_event_uuid(event_uuid, task_uuid);
+
+ if (sais_event_db_ensure_open(vhd, event_uuid, 0, &pdb)) {
+ lwsl_err("%s: unable to open event-specific database\n",
+ __func__);
+
+ return SAI_DB_RESULT_ERROR;
+ }
+
+ lws_sql_purify(esc, task_uuid, sizeof(esc));
+ lws_snprintf(cmd, sizeof(cmd), " and uuid='%s'", esc);
+ ret = lws_struct_sq3_deserialize(pdb, cmd, NULL,
+ lsm_schema_sq3_map_task, &o, &ac, 0, 1);
+ if (ret < 0 || !o.head) {
+ sais_event_db_close(vhd, &pdb);
+ lwsac_free(&ac);
+ return SAI_DB_RESULT_ERROR;
+ }
+
+ task = lws_container_of(o.head, sai_task_t, list);
+
+ if (task->build_step > 0) {
+ lws_snprintf(cmd, sizeof(cmd),
+ "update tasks set build_step=%d where uuid='%s'",
+ task->build_step - 1, esc);
+
+ ret = sqlite3_exec(pdb, cmd, NULL, NULL, NULL);
+ if (ret != SQLITE_OK) {
+ sais_event_db_close(vhd, &pdb);
+ lwsac_free(&ac);
+ if (ret == SQLITE_BUSY)
+ return SAI_DB_RESULT_BUSY;
+
+ lwsl_err("%s: %s: %s: fail\n", __func__, cmd,
+ sqlite3_errmsg(pdb));
+ return SAI_DB_RESULT_ERROR;
+ }
+ }
+
+ lwsac_free(&ac);
+ sais_event_db_close(vhd, &pdb);
+
+ sais_set_task_state(vhd, NULL, NULL, task_uuid, SAIES_WAITING, 0, 0);
+
+ sais_task_stop_on_builders(vhd, task_uuid);
+
+ lwsl_err("%s: scheduling sul_central to find a new task\n", __func__);
+ lws_sul_schedule(vhd->context, 0, &vhd->sul_central, sais_central_cb, 1);
+
+ sais_platforms_with_tasks_pending(vhd);
+
+ lwsl_notice("%s: exiting OK\n", __func__);
+
+ return SAI_DB_RESULT_OK;
+}
+
/*
* Look for any task on any event that needs building on platform_name, if found
* the caller must take responsibility to free pss->a.ac
diff --git a/src/server/s-websrv.c b/src/server/s-websrv.c
index 58ac7d5..16e2fa8 100644
--- a/src/server/s-websrv.c
+++ b/src/server/s-websrv.c
@@ -77,6 +77,8 @@ static const lws_struct_map_t lsm_schema_json_map[] = {
LSM_SCHEMA (sai_browse_rx_evinfo_t, NULL, lsm_browser_taskreset,
/* shares struct */ "com.warmcat.sai.taskreset"),
LSM_SCHEMA (sai_browse_rx_evinfo_t, NULL, lsm_browser_taskreset,
+ /* shares struct */ "com.warmcat.sai.taskrebuildlaststep"),
+ LSM_SCHEMA (sai_browse_rx_evinfo_t, NULL, lsm_browser_taskreset,
/* shares struct */ "com.warmcat.sai.eventreset"),
LSM_SCHEMA (sai_browse_rx_evinfo_t, NULL, lsm_browser_taskreset,
/* shares struct */ "com.warmcat.sai.eventdelete"),
@@ -92,6 +94,7 @@ static const lws_struct_map_t lsm_schema_json_map[] = {
enum {
SAIS_WS_WEBSRV_RX_TASKRESET,
+ SAIS_WS_WEBSRV_RX_TASKREBUILDLASTSTEP,
SAIS_WS_WEBSRV_RX_EVENTRESET,
SAIS_WS_WEBSRV_RX_EVENTDELETE,
SAIS_WS_WEBSRV_RX_TASKCANCEL,
@@ -593,6 +596,18 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
break;
}
+ case SAIS_WS_WEBSRV_RX_TASKREBUILDLASTSTEP:
+ {
+ ei = (sai_browse_rx_evinfo_t *)a.dest;
+ if (sais_validate_id(ei->event_hash, SAI_TASKID_LEN))
+ goto soft_error;
+
+ lwsl_ss_warn(m->ss, "SAIS_WS_WEBSRV_RX_TASKREBUILDLASTSTEP: %s: received", ei->event_hash);
+ if (sais_task_rebuild_last_step(m->vhd, ei->event_hash))
+ lwsl_ss_err(m->ss, "taskrebuildlaststep failed");
+ break;
+ }
+
case SAIS_WS_WEBSRV_RX_EVENTRESET:
{
sai_db_result_t r;
diff --git a/src/server/s-ws-builder.c b/src/server/s-ws-builder.c
index 5e2d59b..0702730 100644
--- a/src/server/s-ws-builder.c
+++ b/src/server/s-ws-builder.c
@@ -712,8 +712,8 @@ bail:
__func__, cb->name,
rej->task_uuid[0] ? rej->task_uuid : "none");
-// if (rej->task_uuid[0])
-// sais_task_reset(vhd, rej->task_uuid, 1);
+ if (rej->task_uuid[0])
+ sais_task_reset(vhd, rej->task_uuid, 1);
lwsac_free(&pss->a.ac);
break;
diff --git a/src/web/w-ws-browser.c b/src/web/w-ws-browser.c
index 0489d3d..44e3961 100644
--- a/src/web/w-ws-browser.c
+++ b/src/web/w-ws-browser.c
@@ -69,6 +69,8 @@ static const lws_struct_map_t lsm_schema_json_map_bwsrx[] = {
LSM_SCHEMA (sai_browse_rx_evinfo_t, NULL, lsm_browser_taskreset,
/* shares struct */ "com.warmcat.sai.taskreset"),
LSM_SCHEMA (sai_browse_rx_evinfo_t, NULL, lsm_browser_taskreset,
+ /* shares struct */ "com.warmcat.sai.taskrebuildlaststep"),
+ LSM_SCHEMA (sai_browse_rx_evinfo_t, NULL, lsm_browser_taskreset,
/* shares struct */ "com.warmcat.sai.eventreset"),
LSM_SCHEMA (sai_browse_rx_evinfo_t, NULL, lsm_browser_taskreset,
/* shares struct */ "com.warmcat.sai.eventdelete"),
@@ -86,6 +88,7 @@ enum {
SAIM_WS_BROWSER_RX_TASKINFO,
SAIM_WS_BROWSER_RX_EVENTINFO,
SAIM_WS_BROWSER_RX_TASKRESET,
+ SAIM_WS_BROWSER_RX_TASKREBUILDLASTSTEP,
SAIM_WS_BROWSER_RX_EVENTRESET,
SAIM_WS_BROWSER_RX_EVENTDELETE,
SAIM_WS_BROWSER_RX_TASKCANCEL,
@@ -507,6 +510,19 @@ saiw_ws_json_rx_browser(struct vhd *vhd, struct pss *pss, uint8_t *buf,
saiw_websrv_queue_tx(vhd->h_ss_websrv, buf, bl, ss_flags);
break;
+ case SAIM_WS_BROWSER_RX_TASKREBUILDLASTSTEP:
+ if (!sais_conn_auth(pss))
+ goto auth_error;
+
+ /*
+ * User is asking us to rebuild the last step of this task
+ */
+
+ ei = (sai_browse_rx_evinfo_t *)a.dest;
+
+ saiw_websrv_queue_tx(vhd->h_ss_websrv, buf, bl, ss_flags);
+ break;
+
case SAIM_WS_BROWSER_RX_EVENTRESET:
if (!sais_conn_auth(pss))