Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
 
root / READMEs / README-build-bsds.md
Author[]Andy Green <andy@warmcat.com> 2026-04-13 09:28 UTC
Committer[]Andy Green <andy@warmcat.com> 2026-04-13 11:18 UTC
Treeb2cad3c916e559f4641268b9bb97b51b9c51ee2c   Raw Patch
 
event-delete
event-delete
diff --git a/src/builder/b-nspawn.c b/src/builder/b-nspawn.c index ad60019..3022362 100644 --- a/src/builder/b-nspawn.c +++ b/src/builder/b-nspawn.c @@ -512,6 +512,7 @@ saib_spawn_script(struct sai_nspawn *ns) const char *env[] = { "PATH=/usr/local/bin:/usr/bin:/bin", "LANG=en_US.UTF-8", + "TERM=xterm-256color", NULL }; char one_step[4096]; diff --git a/src/builder/b-ws-server.c b/src/builder/b-ws-server.c index 2f1e344..272e84e 100644 --- a/src/builder/b-ws-server.c +++ b/src/builder/b-ws-server.c @@ -186,7 +186,22 @@ saib_m_rx(void *userobj, const uint8_t *in, size_t len, int flags) can = (sai_cancel_t *)a.dest; - lwsl_notice("%s: received task cancel for %s\n", __func__, can->task_uuid); + lwsl_notice("%s: received task cancel for %s, erase %d\n", __func__, can->task_uuid, can->erase); + + if (can->erase) { +#if !defined(WIN32) + if (write(builder.pipe_master_wr, can->task_uuid, + LWS_POSIX_LENGTH_CAST(strlen(can->task_uuid))) != (ssize_t)strlen(can->task_uuid)) + lwsl_err("%s: failed to write to deletion worker\n", + __func__); +#else + DWORD written; + if (!WriteFile(builder.pipe_master_wr_win, can->task_uuid, + (DWORD)strlen(can->task_uuid), &written, NULL)) + lwsl_err("%s: failed to write to deletion worker\n", + __func__); +#endif + } lws_start_foreach_dll_safe(struct lws_dll2 *, mp, mp1, builder.sai_plat_owner.head) { diff --git a/src/common/include/private.h b/src/common/include/private.h index 222cedc..d316703 100644 --- a/src/common/include/private.h +++ b/src/common/include/private.h @@ -268,6 +268,7 @@ typedef struct sai_rejection { typedef struct sai_cancel { struct lws_dll2 list; char task_uuid[65]; + unsigned int erase; } sai_cancel_t; /* @@ -718,7 +719,7 @@ extern const lws_struct_map_t lsm_plat_list[1], lsm_schema_map_plat[1], lsm_task_rej[4], - lsm_task_cancel[1], + lsm_task_cancel[2], lsm_schema_json_map_can[1], lsm_schema_json_map_task[1], lsm_schema_json_map_event[1], diff --git a/src/common/struct-metadata.c b/src/common/struct-metadata.c index 85b6f9a..1c9dd09 100644 --- a/src/common/struct-metadata.c +++ b/src/common/struct-metadata.c @@ -203,6 +203,7 @@ const lws_struct_map_t lsm_schema_json_task_rej[] = { const lws_struct_map_t lsm_task_cancel[] = { LSM_CARRAY (sai_cancel_t, task_uuid, "task_uuid"), + LSM_UNSIGNED (sai_cancel_t, erase, "erase"), }; const lws_struct_map_t lsm_rebuild[] = { diff --git a/src/server/s-central.c b/src/server/s-central.c index 122204b..aff0f0c 100644 --- a/src/server/s-central.c +++ b/src/server/s-central.c @@ -186,6 +186,82 @@ sais_ensure_tables(struct vhd *vhd) } void +sais_central_gc_deleted_events_cb(lws_sorted_usec_list_t *sul) +{ + struct vhd *vhd = lws_container_of(sul, struct vhd, sul_gc_events); + char q[128], event_uuid[65], esc[96]; + sqlite3_stmt *sm, *tsm; + sqlite3 *pdb = NULL; + + /* Find one event that is in SAIES_DELETED (7) state */ + lws_snprintf(q, sizeof(q), "SELECT uuid FROM events WHERE state = %d LIMIT 1", SAIES_DELETED); + + if (sqlite3_prepare_v2(vhd->server.pdb, q, -1, &sm, NULL) != SQLITE_OK) + return; + + if (sqlite3_step(sm) != SQLITE_ROW) { + sqlite3_finalize(sm); + return; /* Nothing to GC */ + } + + lws_strncpy(event_uuid, (const char *)sqlite3_column_text(sm, 0), sizeof(event_uuid)); + sqlite3_finalize(sm); + + if (sai_event_db_ensure_open(vhd->context, &vhd->sqlite3_cache, + vhd->sqlite3_path_lhs, event_uuid, 0, &pdb)) + return; + + /* Pick 1 task that is stopped to garbage collect */ + /* 0=WAITING, 3=SUCCESS, 4=FAIL, 5=CANCELLED */ + lws_snprintf(q, sizeof(q), "SELECT uuid FROM tasks WHERE state IN (0, 3, 4, 5) LIMIT 1"); + + if (sqlite3_prepare_v2(pdb, q, -1, &tsm, NULL) == SQLITE_OK) { + if (sqlite3_step(tsm) == SQLITE_ROW) { + const char *u = (const char *)sqlite3_column_text(tsm, 0); + if (u) { + char tu[65]; + lws_strncpy(tu, u, sizeof(tu)); + lws_sql_purify(esc, tu, sizeof(esc)); + + sais_task_cancel(vhd, tu, 1); + + lws_snprintf(q, sizeof(q), "DELETE FROM logs WHERE task_uuid='%s'", esc); + sqlite3_exec(pdb, q, NULL, NULL, NULL); + + lws_snprintf(q, sizeof(q), "DELETE FROM artifacts WHERE task_uuid='%s'", esc); + sqlite3_exec(pdb, q, NULL, NULL, NULL); + + lws_snprintf(q, sizeof(q), "DELETE FROM tasks WHERE uuid='%s'", esc); + sqlite3_exec(pdb, q, NULL, NULL, NULL); + } + } + sqlite3_finalize(tsm); + } + + /* Check if the event DB is completely empty of tasks now */ + int remaining = 1; /* Assume 1 just in case query fails */ + if (sqlite3_prepare_v2(pdb, "SELECT count(*) FROM tasks", -1, &tsm, NULL) == SQLITE_OK) { + if (sqlite3_step(tsm) == SQLITE_ROW) + remaining = sqlite3_column_int(tsm, 0); + sqlite3_finalize(tsm); + } + sai_event_db_close(&vhd->sqlite3_cache, &pdb); + + if (remaining == 0) { + /* Everything is gone, we can delete the logical event and unlink the sqlite files safely */ + lws_sql_purify(esc, event_uuid, sizeof(esc)); + lws_snprintf(q, sizeof(q), "DELETE FROM events WHERE uuid='%s'", esc); + sqlite3_exec(vhd->server.pdb, q, NULL, NULL, NULL); + sai_event_db_delete_database(vhd->sqlite3_path_lhs, event_uuid); + lwsl_notice("%s: Completed GC for deleted event %s\n", __func__, event_uuid); + } + + /* Keep yielding and re-scheduling as long as there's still work to do on this or other events */ + lws_sul_schedule(vhd->context, 0, &vhd->sul_gc_events, + sais_central_gc_deleted_events_cb, 10 * LWS_US_PER_MS); /* 10ms for next task */ +} + +void sais_central_cb(lws_sorted_usec_list_t *sul) { struct vhd *vhd = lws_container_of(sul, struct vhd, sul_central); @@ -214,6 +290,10 @@ sais_central_cb(lws_sorted_usec_list_t *sul) sais_prune_inflight_list(vhd); sais_platforms_with_tasks_pending(vhd); + if (!vhd->sul_gc_events.list.owner) + lws_sul_schedule(context, 0, &vhd->sul_gc_events, + sais_central_gc_deleted_events_cb, 10 * LWS_US_PER_MS); + /* check again in 1s */ lws_sul_schedule(context, 0, &vhd->sul_central, sais_central_cb, diff --git a/src/server/s-private.h b/src/server/s-private.h index f3b3f7a..0f31e8a 100644 --- a/src/server/s-private.h +++ b/src/server/s-private.h @@ -231,6 +231,7 @@ struct vhd { lws_sorted_usec_list_t sul_logcache; lws_sorted_usec_list_t sul_central; /* background task allocation sul */ lws_sorted_usec_list_t sul_activity; /* activity broadcast sul */ + lws_sorted_usec_list_t sul_gc_events; /* incremental GC of deleted events */ lws_usec_t last_check_abandoned_tasks; @@ -292,13 +293,16 @@ sais_central_cb(lws_sorted_usec_list_t *sul); void sais_activity_cb(lws_sorted_usec_list_t *sul); +void +sais_central_gc_deleted_events_cb(lws_sorted_usec_list_t *sul); + sai_db_result_t sais_task_clear_build_and_logs(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); +sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase); int sais_allocate_task(struct vhd *vhd, struct pss *pss, sai_plat_t *cb, @@ -400,7 +404,7 @@ void sais_get_task_metrics_estimates(struct vhd *vhd, sai_task_t *task); int -sais_task_cancel(struct vhd *vhd, const char *task_uuid); +sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase); int sais_task_stop_on_builders(struct vhd *vhd, const char *task_uuid); diff --git a/src/server/s-task-helpers.c b/src/server/s-task-helpers.c index f2cfec6..cf07ca8 100644 --- a/src/server/s-task-helpers.c +++ b/src/server/s-task-helpers.c @@ -418,7 +418,7 @@ sais_task_pause(struct vhd *vhd, const char *task_uuid) } int -sais_task_cancel(struct vhd *vhd, const char *task_uuid) +sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase) { sai_cancel_t *can; @@ -438,6 +438,7 @@ sais_task_cancel(struct vhd *vhd, const char *task_uuid) memset(can, 0, sizeof(*can)); lws_strncpy(can->task_uuid, task_uuid, sizeof(can->task_uuid)); + can->erase = (unsigned int)erase; lws_dll2_add_tail(&can->list, &pss->task_cancel_owner); @@ -526,6 +527,7 @@ sais_task_stop_on_builders(struct vhd *vhd, const char *task_uuid) memset(can, 0, sizeof(*can)); lws_strncpy(can->task_uuid, task_uuid, sizeof(can->task_uuid)); + can->erase = 0; lws_dll2_add_tail(&can->list, &pss_match->task_cancel_owner); lws_callback_on_writable(pss_match->wsi); diff --git a/src/server/s-task.c b/src/server/s-task.c index 901fa09..a040e58 100644 --- a/src/server/s-task.c +++ b/src/server/s-task.c @@ -172,7 +172,7 @@ sais_task_pending(struct vhd *vhd, struct pss *pss, sai_plat_t *cb, const char *platform) { struct lwsac *ac = NULL, *failed_ac = NULL; - char esc_plat[96], pf[2048], query[384]; + char esc_plat[96], esc_bname[128], pf[2048], query[384]; lws_dll2_owner_t o, failed_tasks_owner; typedef struct sai_failed_task_info { lws_dll2_t list; @@ -184,6 +184,7 @@ sais_task_pending(struct vhd *vhd, struct pss *pss, sai_plat_t *cb, int n; lws_sql_purify(esc_plat, platform, sizeof(esc_plat)); + lws_sql_purify(esc_bname, cb->name, sizeof(esc_bname)); assert(platform); /* @@ -233,7 +234,9 @@ sais_task_pending(struct vhd *vhd, struct pss *pss, sai_plat_t *cb, */ lws_snprintf(query, sizeof(query), "select count(state) from tasks where " - "(state = 0 or state = 9) and platform = '%s'", esc_plat); + "(state = 0 or state = 9) and platform = '%s' and " + "(builder_name IS NULL or builder_name = '' or builder_name = '%s')", + esc_plat, esc_bname); m = sqlite3_exec(pdb, query, sql3_get_integer_cb, &pending_count, NULL); if (m != SQLITE_OK) { @@ -365,8 +368,9 @@ sais_task_pending(struct vhd *vhd, struct pss *pss, sai_plat_t *cb, lws_sql_purify(esc_taskname, fti->taskname, sizeof(esc_taskname)); lws_snprintf(pf, sizeof(pf), " and (state == 0 or state == 9) and " - "(platform == '%s') and (taskname == '%s')", - esc_plat, esc_taskname); + "(platform == '%s') and (taskname == '%s') and " + "(builder_name IS NULL or builder_name == '' or builder_name == '%s')", + esc_plat, esc_taskname, esc_bname); lwsac_free(&pss->ac_alloc_task); lws_dll2_owner_clear(&owner); @@ -395,8 +399,9 @@ next1: ; /* We have fallen back to doing tasks earliest-first */ lws_snprintf(pf, sizeof(pf), - " and (state = 0 or state = 9) and (platform = '%s')", - esc_plat); + " and (state = 0 or state = 9) and (platform = '%s') and " + "(builder_name IS NULL or builder_name = '' or builder_name = '%s')", + esc_plat, esc_bname); lwsac_free(&pss->ac_alloc_task); lws_dll2_owner_t owner; diff --git a/src/server/s-webops.c b/src/server/s-webops.c index f2f9444..496ec83 100644 --- a/src/server/s-webops.c +++ b/src/server/s-webops.c @@ -272,65 +272,27 @@ sai_db_result_t sais_event_delete(struct vhd *vhd, const char *event_uuid) { char qu[128], esc[96], pre[LWS_PRE + 128]; - struct lwsac *ac = NULL; lws_wsmsg_info_t info; sqlite3 *pdb = NULL; - lws_dll2_owner_t o; char *err = NULL; + sqlite3_stmt *sm; size_t len; int ret; - if (sai_event_db_ensure_open(vhd->context, &vhd->sqlite3_cache, - vhd->sqlite3_path_lhs, event_uuid, 0, &pdb) == 0) { - if (lws_struct_sq3_deserialize(pdb, NULL, NULL, - lsm_schema_sq3_map_task, - &o, &ac, 0, 999) >= 0) { - - ret = sqlite3_exec(pdb, "BEGIN TRANSACTION", NULL, NULL, &err); - if (ret != SQLITE_OK) { - sai_event_db_close(&vhd->sqlite3_cache, &pdb); - lwsac_free(&ac); - if (ret == SQLITE_BUSY) - return SAI_DB_RESULT_BUSY; - return SAI_DB_RESULT_ERROR; - } - - lws_start_foreach_dll(struct lws_dll2 *, p, o.head) { - sai_task_t *t = lws_container_of(p, sai_task_t, list); - - if (t->state != SAIES_WAITING && - t->state != SAIES_SUCCESS && - t->state != SAIES_FAIL && - t->state != SAIES_CANCELLED) - sais_task_cancel(vhd, t->uuid); - - } lws_end_foreach_dll(p); - - ret = sqlite3_exec(pdb, "END TRANSACTION", NULL, NULL, &err); - if (ret != SQLITE_OK) { - sai_event_db_close(&vhd->sqlite3_cache, &pdb); - lwsac_free(&ac); - if (ret == SQLITE_BUSY) - return SAI_DB_RESULT_BUSY; - return SAI_DB_RESULT_ERROR; - } - } - sai_event_db_close(&vhd->sqlite3_cache, &pdb); - lwsac_free(&ac); - } - lws_sql_purify(esc, event_uuid, sizeof(esc)); - lws_snprintf(qu, sizeof(qu), "delete from events where uuid='%s'", esc); + + /* 1. Mark event as SAIES_DELETED immediately so it disappears from UI */ + lws_snprintf(qu, sizeof(qu), "update events set state=%d where uuid='%s'", SAIES_DELETED, esc); ret = sqlite3_exec(vhd->server.pdb, qu, NULL, NULL, &err); if (ret != SQLITE_OK) { if (ret == SQLITE_BUSY) return SAI_DB_RESULT_BUSY; - lwsl_err("%s: evdel uuid %s, sq3 err %s\n", __func__, esc, err); + lwsl_err("%s: evdel mark uuid %s, sq3 err %s\n", __func__, esc, err); sqlite3_free(err); return SAI_DB_RESULT_ERROR; } - sai_event_db_delete_database(vhd->sqlite3_path_lhs, event_uuid); + /* 2. Broadcast change to UI */ sais_eventchange(vhd->h_ss_websrv, event_uuid, SAIES_DELETED); len = (size_t)lws_snprintf(pre + LWS_PRE, sizeof(pre) - LWS_PRE, @@ -347,6 +309,28 @@ sais_event_delete(struct vhd *vhd, const char *event_uuid) return SAI_DB_RESULT_ERROR; } + /* 3. Drop active builders gracefully without loading huge JSON objects */ + if (sai_event_db_ensure_open(vhd->context, &vhd->sqlite3_cache, + vhd->sqlite3_path_lhs, event_uuid, 0, &pdb) == 0) { + lws_snprintf(qu, sizeof(qu), "SELECT uuid FROM tasks WHERE state != 0 AND state != 3 AND state != 4 AND state != 5"); + if (sqlite3_prepare_v2(pdb, qu, -1, &sm, NULL) == SQLITE_OK) { + while (sqlite3_step(sm) == SQLITE_ROW) { + const unsigned char *task_uuid = sqlite3_column_text(sm, 0); + if (task_uuid) + sais_task_cancel(vhd, (const char *)task_uuid, 0); + } + sqlite3_finalize(sm); + } + sai_event_db_close(&vhd->sqlite3_cache, &pdb); + } + + /* + * Incrementally garbage collect the tasks later in sais_central_cb, + * which eventually drops the DB and erases the event row entirely. + */ + lws_sul_schedule(vhd->context, 0, &vhd->sul_gc_events, + sais_central_gc_deleted_events_cb, 1); + /* * Recompute startable task platforms and broadcast to all sai-power, * after there has been a change in tasks diff --git a/src/server/s-ws-web.c b/src/server/s-ws-web.c index 70377d9..5311f09 100644 --- a/src/server/s-ws-web.c +++ b/src/server/s-ws-web.c @@ -597,7 +597,7 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags) if (sais_validate_id(ei->event_hash, SAI_TASKID_LEN)) goto soft_error; - sais_task_cancel(m->vhd, ei->event_hash); + sais_task_cancel(m->vhd, ei->event_hash, 0); break; diff --git a/src/web/w-ws-browser.c b/src/web/w-ws-browser.c index fef69ef..fb45c88 100644 --- a/src/web/w-ws-browser.c +++ b/src/web/w-ws-browser.c @@ -887,17 +887,17 @@ saiw_browser_queue_overview(struct vhd *vhd, struct pss *pss) if (pss->specific_project[0]) { lws_sql_purify(esc, pss->specific_project, sizeof(esc) - 1); - lws_snprintf(filt, sizeof(filt), " and repo_name=\"%s\"", esc); + lws_snprintf(filt, sizeof(filt), " and state != %d and repo_name=\"%s\"", SAIES_DELETED, esc); n = -1; + } else { + lws_snprintf(filt, sizeof(filt), " and state != %d", SAIES_DELETED); } unsigned int total_events = 0; { char q[256]; sqlite3_stmt *stmt; - lws_snprintf(q, sizeof(q), "SELECT COUNT(*) FROM events%s%s", - filt[0] ? " WHERE " : "", - filt[0] ? filt + 5 : ""); + lws_snprintf(q, sizeof(q), "SELECT COUNT(*) FROM events WHERE %s", filt + 5); if (sqlite3_prepare_v2(vhd->pdb, q, -1, &stmt, NULL) == SQLITE_OK) { if (sqlite3_step(stmt) == SQLITE_ROW) total_events = (unsigned int)sqlite3_column_int(stmt, 0);
Page fetched 0s ago, creation time: 8ms (vhost etag hits: 0%, cache hits: 0%)