Fossil SCM

fossil-scm / src / backoffice.c
Source Blame History 890 lines
947081a… drh 1 /*
947081a… drh 2 ** Copyright (c) 2018 D. Richard Hipp
947081a… drh 3 **
947081a… drh 4 ** This program is free software; you can redistribute it and/or
947081a… drh 5 ** modify it under the terms of the Simplified BSD License (also
947081a… drh 6 ** known as the "2-Clause License" or "FreeBSD License".)
947081a… drh 7 **
947081a… drh 8 ** This program is distributed in the hope that it will be useful,
947081a… drh 9 ** but without any warranty; without even the implied warranty of
947081a… drh 10 ** merchantability or fitness for a particular purpose.
947081a… drh 11 **
947081a… drh 12 ** Author contact information:
947081a… drh 13 ** [email protected]
947081a… drh 14 ** http://www.hwaci.com/drh/
947081a… drh 15 **
947081a… drh 16 *******************************************************************************
947081a… drh 17 **
947081a… drh 18 ** This file contains code used to manage a background processes that
947081a… drh 19 ** occur after user interaction with the repository. Examples of
947081a… drh 20 ** backoffice processing includes:
947081a… drh 21 **
947081a… drh 22 ** * Sending alerts and notifications
947081a… drh 23 ** * Processing the email queue
9d8db79… drh 24 ** * Handling post-receive hooks
947081a… drh 25 ** * Automatically syncing to peer repositories
947081a… drh 26 **
947081a… drh 27 ** Backoffice processing is automatically started whenever there are
947081a… drh 28 ** changes to the repository. The backoffice process dies off after
947081a… drh 29 ** a period of inactivity.
947081a… drh 30 **
947081a… drh 31 ** Steps are taken to ensure that only a single backoffice process is
947081a… drh 32 ** running at a time. Otherwise, there could be race conditions that
947081a… drh 33 ** cause adverse effects such as multiple alerts for the same changes.
947081a… drh 34 **
947081a… drh 35 ** At the same time, we do not want a backoffice process to run forever.
947081a… drh 36 ** Backoffice processes should die off after doing whatever work they need
947081a… drh 37 ** to do. In this way, we avoid having lots of idle processes in the
947081a… drh 38 ** process table, doing nothing on rarely accessed repositories, and
947081a… drh 39 ** if the Fossil binary is updated on a system, the backoffice processes
947081a… drh 40 ** will restart using the new binary automatically.
4180dc6… drh 41 **
4180dc6… drh 42 ** At any point in time there should be at most two backoffice processes.
a46e128… drh 43 ** There is a main process that is doing the actual work, and there is
4180dc6… drh 44 ** a second stand-by process that is waiting for the main process to finish
4180dc6… drh 45 ** and that will become the main process after a delay.
4180dc6… drh 46 **
4180dc6… drh 47 ** After any successful web page reply, the backoffice_check_if_needed()
4180dc6… drh 48 ** routine is called. That routine checks to see if both one or both of
4180dc6… drh 49 ** the backoffice processes are already running. That routine remembers the
4180dc6… drh 50 ** status in a global variable.
4180dc6… drh 51 **
4180dc6… drh 52 ** Later, after the repository database is closed, the
4180dc6… drh 53 ** backoffice_run_if_needed() routine is called. If the prior call
4180dc6… drh 54 ** to backoffice_check_if_needed() indicated that backoffice processing
4180dc6… drh 55 ** might be required, the run_if_needed() attempts to kick off a backoffice
4180dc6… drh 56 ** process.
4180dc6… drh 57 **
a46e128… drh 58 ** All work performed by the backoffice is in the backoffice_work()
4180dc6… drh 59 ** routine.
947081a… drh 60 */
864a6f3… mistachkin 61 #if defined(_WIN32)
864a6f3… mistachkin 62 # if defined(_WIN32_WINNT)
864a6f3… mistachkin 63 # undef _WIN32_WINNT
864a6f3… mistachkin 64 # endif
864a6f3… mistachkin 65 # define _WIN32_WINNT 0x501
864a6f3… mistachkin 66 #endif
947081a… drh 67 #include "config.h"
947081a… drh 68 #include "backoffice.h"
947081a… drh 69 #include <time.h>
947081a… drh 70 #if defined(_WIN32)
947081a… drh 71 # include <windows.h>
2583cae… drh 72 # include <stdio.h>
2583cae… drh 73 # include <process.h>
3006826… mistachkin 74 # if defined(__MINGW32__)
3006826… mistachkin 75 # include <wchar.h>
3006826… mistachkin 76 # endif
43c2987… drh 77 # define GETPID (int)GetCurrentProcessId
947081a… drh 78 #else
07356e4… drh 79 # include <unistd.h>
947081a… drh 80 # include <sys/types.h>
947081a… drh 81 # include <signal.h>
88240d4… drh 82 # include <errno.h>
71b9f35… drh 83 # include <sys/time.h>
71b9f35… drh 84 # include <sys/resource.h>
918e1dd… drh 85 # include <fcntl.h>
43c2987… drh 86 # define GETPID getpid
947081a… drh 87 #endif
1021afc… drh 88 #include <time.h>
947081a… drh 89
947081a… drh 90 /*
947081a… drh 91 ** The BKOFCE_LEASE_TIME is the amount of time for which a single backoffice
947081a… drh 92 ** processing run is valid. Each backoffice run monopolizes the lease for
947081a… drh 93 ** at least this amount of time. Hopefully all backoffice processing is
947081a… drh 94 ** finished much faster than this - usually in less than a second. But
4180dc6… drh 95 ** regardless of how long each invocation lasts, successive backoffice runs
947081a… drh 96 ** must be spaced out by at least this much time.
947081a… drh 97 */
4180dc6… drh 98 #define BKOFCE_LEASE_TIME 60 /* Length of lease validity in seconds */
947081a… drh 99
947081a… drh 100 #if LOCAL_INTERFACE
947081a… drh 101 /*
947081a… drh 102 ** An instance of the following object describes a lease on the backoffice
947081a… drh 103 ** processing timeslot. This lease is used to help ensure that no more than
4180dc6… drh 104 ** one process is running backoffice at a time.
947081a… drh 105 */
947081a… drh 106 struct Lease {
4180dc6… drh 107 sqlite3_uint64 idCurrent; /* process ID for the current lease holder */
4180dc6… drh 108 sqlite3_uint64 tmCurrent; /* Expiration of the current lease */
4180dc6… drh 109 sqlite3_uint64 idNext; /* process ID for the next lease holder on queue */
4180dc6… drh 110 sqlite3_uint64 tmNext; /* Expiration of the next lease */
947081a… drh 111 };
947081a… drh 112 #endif
5294302… drh 113
4180dc6… drh 114 /***************************************************************************
4180dc6… drh 115 ** Local state variables
4180dc6… drh 116 **
4180dc6… drh 117 ** Set to prevent backoffice processing from ever entering sleep or
5294302… drh 118 ** otherwise taking a long time to complete. Set this when a user-visible
5294302… drh 119 ** process might need to wait for backoffice to complete.
5294302… drh 120 */
5294302… drh 121 static int backofficeNoDelay = 0;
5294302… drh 122
4180dc6… drh 123 /* This variable is set to the name of a database on which backoffice
4180dc6… drh 124 ** should run if backoffice process is needed. It is set by the
4180dc6… drh 125 ** backoffice_check_if_needed() routine which must be run while the database
4180dc6… drh 126 ** file is open. Later, after the database is closed, the
4180dc6… drh 127 ** backoffice_run_if_needed() will consult this variable to see if it
4180dc6… drh 128 ** should be a no-op.
71b9f35… drh 129 **
71b9f35… drh 130 ** The magic string "x" in this variable means "do not run the backoffice".
4180dc6… drh 131 */
4180dc6… drh 132 static char *backofficeDb = 0;
71b9f35… drh 133
71b9f35… drh 134 /*
71b9f35… drh 135 ** Log backoffice activity to a file named here. If not NULL, this
71b9f35… drh 136 ** overrides the "backoffice-logfile" setting of the database. If NULL,
71b9f35… drh 137 ** the "backoffice-logfile" setting is used instead.
71b9f35… drh 138 */
c7dca0c… drh 139 static const char *backofficeLogfile = 0;
c7dca0c… drh 140
c7dca0c… drh 141 /*
e05a97a… drh 142 ** Write the log message into this open file.
e05a97a… drh 143 */
e05a97a… drh 144 static FILE *backofficeFILE = 0;
e05a97a… drh 145
e05a97a… drh 146 /*
e05a97a… drh 147 ** Write backoffice log messages on this BLOB. to this connection:
71b9f35… drh 148 */
e05a97a… drh 149 static Blob *backofficeBlob = 0;
71b9f35… drh 150
75b76ef… drh 151 /*
75b76ef… drh 152 ** Non-zero for extra logging detail.
75b76ef… drh 153 */
75b76ef… drh 154 static int backofficeLogDetail = 0;
75b76ef… drh 155
4180dc6… drh 156 /* End of state variables
4180dc6… drh 157 ****************************************************************************/
0fe9da8… mistachkin 158
0fe9da8… mistachkin 159 /*
0fe9da8… mistachkin 160 ** This function emits a diagnostic message related to the processing in
0fe9da8… mistachkin 161 ** this module.
0fe9da8… mistachkin 162 */
0fe9da8… mistachkin 163 #if defined(_WIN32)
0fe9da8… mistachkin 164 # define BKOFCE_ALWAYS_TRACE (1)
250fc00… mistachkin 165 extern void sqlite3_win32_write_debug(const char *, int);
0fe9da8… mistachkin 166 #else
0fe9da8… mistachkin 167 # define BKOFCE_ALWAYS_TRACE (0)
0fe9da8… mistachkin 168 #endif
0fe9da8… mistachkin 169 static void backofficeTrace(const char *zFormat, ...){
0fe9da8… mistachkin 170 char *zMsg = 0;
0fe9da8… mistachkin 171 if( BKOFCE_ALWAYS_TRACE || g.fAnyTrace ){
0fe9da8… mistachkin 172 va_list ap;
0fe9da8… mistachkin 173 va_start(ap, zFormat);
0fe9da8… mistachkin 174 zMsg = sqlite3_vmprintf(zFormat, ap);
0fe9da8… mistachkin 175 va_end(ap);
0fe9da8… mistachkin 176 #if defined(_WIN32)
0fe9da8… mistachkin 177 sqlite3_win32_write_debug(zMsg, -1);
0fe9da8… mistachkin 178 #endif
0fe9da8… mistachkin 179 }
0fe9da8… mistachkin 180 if( g.fAnyTrace ) fprintf(stderr, "%s", zMsg);
0fe9da8… mistachkin 181 if( zMsg ) sqlite3_free(zMsg);
0fe9da8… mistachkin 182 }
4180dc6… drh 183
5294302… drh 184 /*
4180dc6… drh 185 ** Do not allow backoffice processes to sleep waiting on a timeslot.
4180dc6… drh 186 ** They must either do their work immediately or exit.
4180dc6… drh 187 **
4180dc6… drh 188 ** In a perfect world, this interface would not exist, as there would
4180dc6… drh 189 ** never be a problem with waiting backoffice threads. But in some cases
4180dc6… drh 190 ** a backoffice will delay a UI thread, so we don't want them to run for
4180dc6… drh 191 ** longer than needed.
5294302… drh 192 */
5294302… drh 193 void backoffice_no_delay(void){
5294302… drh 194 backofficeNoDelay = 1;
43c2987… drh 195 }
43c2987… drh 196
43c2987… drh 197 /*
43c2987… drh 198 ** Sleeps for the specified number of milliseconds -OR- until interrupted
43c2987… drh 199 ** by another thread (if supported by the underlying platform). Non-zero
43c2987… drh 200 ** will be returned if the sleep was interrupted.
43c2987… drh 201 */
43c2987… drh 202 static int backofficeSleep(int milliseconds){
43c2987… drh 203 #if defined(_WIN32)
43c2987… drh 204 assert( milliseconds>=0 );
43c2987… drh 205 if( SleepEx((DWORD)milliseconds, TRUE)==WAIT_IO_COMPLETION ){
43c2987… drh 206 return 1;
43c2987… drh 207 }
43c2987… drh 208 #else
43c2987… drh 209 sqlite3_sleep(milliseconds);
43c2987… drh 210 #endif
43c2987… drh 211 return 0;
99fcc43… drh 212 }
947081a… drh 213
947081a… drh 214 /*
947081a… drh 215 ** Parse a unsigned 64-bit integer from a string. Return a pointer
947081a… drh 216 ** to the character of z[] that occurs after the integer.
947081a… drh 217 */
947081a… drh 218 static const char *backofficeParseInt(const char *z, sqlite3_uint64 *pVal){
947081a… drh 219 *pVal = 0;
947081a… drh 220 if( z==0 ) return 0;
947081a… drh 221 while( fossil_isspace(z[0]) ){ z++; }
947081a… drh 222 while( fossil_isdigit(z[0]) ){
947081a… drh 223 *pVal = (*pVal)*10 + z[0] - '0';
947081a… drh 224 z++;
947081a… drh 225 }
947081a… drh 226 return z;
947081a… drh 227 }
947081a… drh 228
947081a… drh 229 /*
947081a… drh 230 ** Read the "backoffice" property and parse it into a Lease object.
ae6e8d9… drh 231 **
ae6e8d9… drh 232 ** The backoffice property should consist of four integers:
ae6e8d9… drh 233 **
ae6e8d9… drh 234 ** (1) Process ID for the active backoffice process.
ae6e8d9… drh 235 ** (2) Time (seconds since 1970) for when the active backoffice
ae6e8d9… drh 236 ** lease expires.
ae6e8d9… drh 237 ** (3) Process ID for the on-deck backoffice process.
ae6e8d9… drh 238 ** (4) Time when the on-deck process should expire.
ae6e8d9… drh 239 **
ae6e8d9… drh 240 ** No other process should start active backoffice processing until
ae6e8d9… drh 241 ** process (1) no longer exists and the current time exceeds (2).
947081a… drh 242 */
947081a… drh 243 static void backofficeReadLease(Lease *pLease){
947081a… drh 244 Stmt q;
947081a… drh 245 memset(pLease, 0, sizeof(*pLease));
f741baa… drh 246 db_unprotect(PROTECT_CONFIG);
947081a… drh 247 db_prepare(&q, "SELECT value FROM repository.config"
947081a… drh 248 " WHERE name='backoffice'");
947081a… drh 249 if( db_step(&q)==SQLITE_ROW ){
947081a… drh 250 const char *z = db_column_text(&q,0);
947081a… drh 251 z = backofficeParseInt(z, &pLease->idCurrent);
947081a… drh 252 z = backofficeParseInt(z, &pLease->tmCurrent);
947081a… drh 253 z = backofficeParseInt(z, &pLease->idNext);
947081a… drh 254 backofficeParseInt(z, &pLease->tmNext);
947081a… drh 255 }
947081a… drh 256 db_finalize(&q);
f741baa… drh 257 db_protect_pop();
ae6e8d9… drh 258 }
ae6e8d9… drh 259
ae6e8d9… drh 260 /*
ae6e8d9… drh 261 ** Return a string that describes how long it has been since the
ae6e8d9… drh 262 ** last backoffice run. The string is obtained from fossil_malloc().
ae6e8d9… drh 263 */
ae6e8d9… drh 264 char *backoffice_last_run(void){
ae6e8d9… drh 265 Lease x;
ae6e8d9… drh 266 sqlite3_uint64 tmNow;
ae6e8d9… drh 267 double rAge;
ae6e8d9… drh 268 backofficeReadLease(&x);
ae6e8d9… drh 269 tmNow = time(0);
ae6e8d9… drh 270 if( x.tmCurrent==0 ){
ae6e8d9… drh 271 return fossil_strdup("never");
ae6e8d9… drh 272 }
ae6e8d9… drh 273 if( tmNow<=(x.tmCurrent-BKOFCE_LEASE_TIME) ){
ae6e8d9… drh 274 return fossil_strdup("moments ago");
ae6e8d9… drh 275 }
ae6e8d9… drh 276 rAge = (tmNow - (x.tmCurrent-BKOFCE_LEASE_TIME))/86400.0;
ae6e8d9… drh 277 return mprintf("%z ago", human_readable_age(rAge));
947081a… drh 278 }
947081a… drh 279
947081a… drh 280 /*
947081a… drh 281 ** Write a lease to the backoffice property
947081a… drh 282 */
947081a… drh 283 static void backofficeWriteLease(Lease *pLease){
f741baa… drh 284 db_unprotect(PROTECT_CONFIG);
947081a… drh 285 db_multi_exec(
947081a… drh 286 "REPLACE INTO repository.config(name,value,mtime)"
947081a… drh 287 " VALUES('backoffice','%lld %lld %lld %lld',now())",
947081a… drh 288 pLease->idCurrent, pLease->tmCurrent,
947081a… drh 289 pLease->idNext, pLease->tmNext);
f741baa… drh 290 db_protect_pop();
43c2987… drh 291 }
43c2987… drh 292
43c2987… drh 293 /*
43c2987… drh 294 ** Check to see if the specified Win32 process is still alive. It
43c2987… drh 295 ** should be noted that even if this function returns non-zero, the
43c2987… drh 296 ** process may die before another operation on it can be completed.
43c2987… drh 297 */
43c2987… drh 298 #if defined(_WIN32)
43c2987… drh 299 #ifndef PROCESS_QUERY_LIMITED_INFORMATION
43c2987… drh 300 # define PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
43c2987… drh 301 #endif
43c2987… drh 302 static int backofficeWin32ProcessExists(DWORD dwProcessId){
43c2987… drh 303 HANDLE hProcess;
43c2987… drh 304 hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,FALSE,dwProcessId);
43c2987… drh 305 if( hProcess==NULL ) return 0;
43c2987… drh 306 CloseHandle(hProcess);
43c2987… drh 307 return 1;
947081a… drh 308 }
43c2987… drh 309 #endif
947081a… drh 310
947081a… drh 311 /*
4180dc6… drh 312 ** Check to see if the process identified by pid is alive. If
5b4d2df… drh 313 ** we cannot prove that the process is dead, return true.
947081a… drh 314 */
947081a… drh 315 static int backofficeProcessExists(sqlite3_uint64 pid){
947081a… drh 316 #if defined(_WIN32)
43c2987… drh 317 return pid>0 && backofficeWin32ProcessExists((DWORD)pid)!=0;
947081a… drh 318 #else
947081a… drh 319 return pid>0 && kill((pid_t)pid, 0)==0;
275da70… danield 320 #endif
947081a… drh 321 }
947081a… drh 322
947081a… drh 323 /*
4180dc6… drh 324 ** Check to see if the process identified by pid has finished. If
5b4d2df… drh 325 ** we cannot prove that the process is still running, return true.
947081a… drh 326 */
947081a… drh 327 static int backofficeProcessDone(sqlite3_uint64 pid){
947081a… drh 328 #if defined(_WIN32)
43c2987… drh 329 return pid<=0 || backofficeWin32ProcessExists((DWORD)pid)==0;
947081a… drh 330 #else
947081a… drh 331 return pid<=0 || kill((pid_t)pid, 0)!=0;
275da70… danield 332 #endif
947081a… drh 333 }
947081a… drh 334
947081a… drh 335 /*
947081a… drh 336 ** Return a process id number for the current process
947081a… drh 337 */
947081a… drh 338 static sqlite3_uint64 backofficeProcessId(void){
43c2987… drh 339 return (sqlite3_uint64)GETPID();
947081a… drh 340 }
07356e4… drh 341
947081a… drh 342
947081a… drh 343 /*
947081a… drh 344 ** COMMAND: test-process-id
947081a… drh 345 **
947081a… drh 346 ** Usage: %fossil [--sleep N] PROCESS-ID ...
947081a… drh 347 **
947081a… drh 348 ** Show the current process id, and also tell whether or not all other
947081a… drh 349 ** processes IDs on the command line are running or not. If the --sleep N
947081a… drh 350 ** option is provide, then sleep for N seconds before exiting.
947081a… drh 351 */
947081a… drh 352 void test_process_id_command(void){
947081a… drh 353 const char *zSleep = find_option("sleep",0,1);
947081a… drh 354 int i;
947081a… drh 355 verify_all_options();
947081a… drh 356 fossil_print("ProcessID for this process: %lld\n", backofficeProcessId());
947081a… drh 357 if( zSleep ) sqlite3_sleep(1000*atoi(zSleep));
947081a… drh 358 for(i=2; i<g.argc; i++){
947081a… drh 359 sqlite3_uint64 x = (sqlite3_uint64)atoi(g.argv[i]);
947081a… drh 360 fossil_print("ProcessId %lld: exists %d done %d\n",
947081a… drh 361 x, backofficeProcessExists(x),
947081a… drh 362 backofficeProcessDone(x));
947081a… drh 363 }
947081a… drh 364 }
947081a… drh 365
4180dc6… drh 366 /*
f26ef80… drh 367 ** COMMAND: test-backoffice-lease
f26ef80… drh 368 **
b2e8347… drh 369 ** Usage: %fossil test-backoffice-lease ?--reset?
f26ef80… drh 370 **
f26ef80… drh 371 ** Print out information about the backoffice "lease" entry in the
f26ef80… drh 372 ** config table that controls whether or not backoffice should run.
b2e8347… drh 373 **
b2e8347… drh 374 ** If the --reset option is given, the backoffice lease is reset.
b2e8347… drh 375 ** The use of the --reset option can be disruptive. It can cause two
b2e8347… drh 376 ** or more backoffice processes to be run simultaneously. Use it with
b2e8347… drh 377 ** caution.
f26ef80… drh 378 */
f26ef80… drh 379 void test_backoffice_lease(void){
f26ef80… drh 380 sqlite3_int64 tmNow = time(0);
f26ef80… drh 381 Lease x;
f26ef80… drh 382 const char *zLease;
f26ef80… drh 383 db_find_and_open_repository(0,0);
b2e8347… drh 384 if( find_option("reset",0,0)!=0 ){
b2e8347… drh 385 db_unprotect(PROTECT_CONFIG);
b2e8347… drh 386 db_multi_exec(
b2e8347… drh 387 "DELETE FROM repository.config WHERE name='backoffice'"
b2e8347… drh 388 );
b2e8347… drh 389 db_protect_pop();
b2e8347… drh 390 }
f26ef80… drh 391 verify_all_options();
f26ef80… drh 392 zLease = db_get("backoffice","");
f26ef80… drh 393 fossil_print("now: %lld\n", tmNow);
f26ef80… drh 394 fossil_print("lease: \"%s\"\n", zLease);
f26ef80… drh 395 backofficeReadLease(&x);
f26ef80… drh 396 fossil_print("idCurrent: %-20lld", x.idCurrent);
f26ef80… drh 397 if( backofficeProcessExists(x.idCurrent) ) fossil_print(" (exists)");
f26ef80… drh 398 if( backofficeProcessDone(x.idCurrent) ) fossil_print(" (done)");
f26ef80… drh 399 fossil_print("\n");
f26ef80… drh 400 fossil_print("tmCurrent: %-20lld", x.tmCurrent);
f26ef80… drh 401 if( x.tmCurrent>0 ){
f26ef80… drh 402 fossil_print(" (now%+d)\n",x.tmCurrent-tmNow);
f26ef80… drh 403 }else{
f26ef80… drh 404 fossil_print("\n");
f26ef80… drh 405 }
f26ef80… drh 406 fossil_print("idNext: %-20lld", x.idNext);
f26ef80… drh 407 if( backofficeProcessExists(x.idNext) ) fossil_print(" (exists)");
f26ef80… drh 408 if( backofficeProcessDone(x.idNext) ) fossil_print(" (done)");
f26ef80… drh 409 fossil_print("\n");
f26ef80… drh 410 fossil_print("tmNext: %-20lld", x.tmNext);
f26ef80… drh 411 if( x.tmNext>0 ){
f26ef80… drh 412 fossil_print(" (now%+d)\n",x.tmNext-tmNow);
f26ef80… drh 413 }else{
f26ef80… drh 414 fossil_print("\n");
f26ef80… drh 415 }
f26ef80… drh 416 }
f26ef80… drh 417
f26ef80… drh 418 /*
4180dc6… drh 419 ** If backoffice processing is needed set the backofficeDb variable to the
4180dc6… drh 420 ** name of the database file. If no backoffice processing is needed,
4180dc6… drh 421 ** this routine makes no changes to state.
947081a… drh 422 */
4180dc6… drh 423 void backoffice_check_if_needed(void){
947081a… drh 424 Lease x;
947081a… drh 425 sqlite3_uint64 tmNow;
4180dc6… drh 426
4180dc6… drh 427 if( backofficeDb ) return;
4180dc6… drh 428 if( g.zRepositoryName==0 ) return;
4180dc6… drh 429 if( g.db==0 ) return;
3f5b254… drh 430 if( !db_table_exists("repository","config") ) return;
2467a35… drh 431 if( db_get_boolean("backoffice-disable",0) ) return;
4180dc6… drh 432 tmNow = time(0);
4180dc6… drh 433 backofficeReadLease(&x);
4180dc6… drh 434 if( x.tmNext>=tmNow && backofficeProcessExists(x.idNext) ){
4180dc6… drh 435 /* Another backoffice process is already queued up to run. This
4180dc6… drh 436 ** process does not need to do any backoffice work. */
4180dc6… drh 437 return;
4180dc6… drh 438 }else{
4180dc6… drh 439 /* We need to run backup to be (at a minimum) on-deck */
4180dc6… drh 440 backofficeDb = fossil_strdup(g.zRepositoryName);
4180dc6… drh 441 }
afb1e5f… drh 442 }
afb1e5f… drh 443
afb1e5f… drh 444 /*
afb1e5f… drh 445 ** Call this routine to disable backoffice
afb1e5f… drh 446 */
afb1e5f… drh 447 void backoffice_disable(void){
afb1e5f… drh 448 backofficeDb = "x";
4180dc6… drh 449 }
4180dc6… drh 450
4180dc6… drh 451 /*
4180dc6… drh 452 ** Check for errors prior to running backoffice_thread() or backoffice_run().
4180dc6… drh 453 */
4180dc6… drh 454 static void backoffice_error_check_one(int *pOnce){
4180dc6… drh 455 if( *pOnce ){
4180dc6… drh 456 fossil_panic("multiple calls to backoffice()");
4180dc6… drh 457 }
4180dc6… drh 458 *pOnce = 1;
947081a… drh 459 if( g.db==0 ){
947081a… drh 460 fossil_panic("database not open for backoffice processing");
947081a… drh 461 }
947081a… drh 462 if( db_transaction_nesting_depth()!=0 ){
0fdca8c… drh 463 fossil_panic("transaction %s not closed prior to backoffice processing",
947081a… drh 464 db_transaction_start_point());
947081a… drh 465 }
4180dc6… drh 466 }
4180dc6… drh 467
4180dc6… drh 468 /* This is the main loop for backoffice processing.
4180dc6… drh 469 **
4180dc6… drh 470 ** If another process is already working as the current backoffice and
4180dc6… drh 471 ** the on-deck backoffice, then this routine returns very quickly
4180dc6… drh 472 ** without doing any work.
4180dc6… drh 473 **
4180dc6… drh 474 ** If no backoffice processes are running at all, this routine becomes
4180dc6… drh 475 ** the main backoffice.
4180dc6… drh 476 **
99a319b… wyoung 477 ** If a primary backoffice is running, but an on-deck backoffice is
02c3468… sdr 478 ** needed, this routine becomes that on-deck backoffice.
4180dc6… drh 479 */
4180dc6… drh 480 static void backoffice_thread(void){
4180dc6… drh 481 Lease x;
4180dc6… drh 482 sqlite3_uint64 tmNow;
4180dc6… drh 483 sqlite3_uint64 idSelf;
4180dc6… drh 484 int lastWarning = 0;
4180dc6… drh 485 int warningDelay = 30;
4180dc6… drh 486 static int once = 0;
4180dc6… drh 487
4f15d34… drh 488 if( sqlite3_db_readonly(g.db, 0) ) return;
503354d… drh 489 if( db_is_protected(PROTECT_READONLY) ) return;
cd53239… drh 490 g.zPhase = "backoffice-pending";
4180dc6… drh 491 backoffice_error_check_one(&once);
947081a… drh 492 idSelf = backofficeProcessId();
947081a… drh 493 while(1){
947081a… drh 494 tmNow = time(0);
947081a… drh 495 db_begin_write();
947081a… drh 496 backofficeReadLease(&x);
947081a… drh 497 if( x.tmNext>=tmNow
947081a… drh 498 && x.idNext!=idSelf
947081a… drh 499 && backofficeProcessExists(x.idNext)
947081a… drh 500 ){
947081a… drh 501 /* Another backoffice process is already queued up to run. This
947081a… drh 502 ** process does not need to do any backoffice work and can stop
947081a… drh 503 ** immediately. */
947081a… drh 504 db_end_transaction(0);
96fc484… drh 505 backofficeTrace("/***** Backoffice Processing Not Needed In %d *****/\n",
96fc484… drh 506 GETPID());
947081a… drh 507 break;
947081a… drh 508 }
947081a… drh 509 if( x.tmCurrent<tmNow && backofficeProcessDone(x.idCurrent) ){
947081a… drh 510 /* This process can start doing backoffice work immediately */
947081a… drh 511 x.idCurrent = idSelf;
947081a… drh 512 x.tmCurrent = tmNow + BKOFCE_LEASE_TIME;
947081a… drh 513 x.idNext = 0;
947081a… drh 514 x.tmNext = 0;
a46e128… drh 515 g.zPhase = "backoffice-work";
947081a… drh 516 backofficeWriteLease(&x);
947081a… drh 517 db_end_transaction(0);
0fe9da8… mistachkin 518 backofficeTrace("/***** Begin Backoffice Processing %d *****/\n",
0fe9da8… mistachkin 519 GETPID());
947081a… drh 520 backoffice_work();
5294302… drh 521 break;
5294302… drh 522 }
c09b251… drh 523 if( backofficeNoDelay || db_get_boolean("backoffice-nodelay",0) ){
5294302… drh 524 /* If the no-delay flag is set, exit immediately rather than queuing
5294302… drh 525 ** up. Assume that some future request will come along and handle any
5294302… drh 526 ** necessary backoffice work. */
5294302… drh 527 db_end_transaction(0);
96fc484… drh 528 backofficeTrace(
96fc484… drh 529 "/***** Backoffice No-Delay Exit For %d *****/\n",
96fc484… drh 530 GETPID());
947081a… drh 531 break;
947081a… drh 532 }
947081a… drh 533 /* This process needs to queue up and wait for the current lease
947081a… drh 534 ** to expire before continuing. */
947081a… drh 535 x.idNext = idSelf;
5542cd4… drh 536 x.tmNext = (tmNow>x.tmCurrent ? tmNow : x.tmCurrent) + BKOFCE_LEASE_TIME;
947081a… drh 537 backofficeWriteLease(&x);
947081a… drh 538 db_end_transaction(0);
0fe9da8… mistachkin 539 backofficeTrace("/***** Backoffice On-deck %d *****/\n", GETPID());
947081a… drh 540 if( x.tmCurrent >= tmNow ){
43c2987… drh 541 if( backofficeSleep(1000*(x.tmCurrent - tmNow + 1)) ){
43c2987… drh 542 /* The sleep was interrupted by a signal from another thread. */
0fe9da8… mistachkin 543 backofficeTrace("/***** Backoffice Interrupt %d *****/\n", GETPID());
43c2987… drh 544 db_end_transaction(0);
43c2987… drh 545 break;
43c2987… drh 546 }
947081a… drh 547 }else{
53db40e… drh 548 if( (sqlite3_uint64)(lastWarning+warningDelay) < tmNow ){
6f1c732… drh 549 sqlite3_int64 runningFor = BKOFCE_LEASE_TIME + tmNow - x.tmCurrent;
7ed4d03… drh 550 if( warningDelay>=240 && runningFor<1800 ){
6f1c732… drh 551 fossil_warning(
947081a… drh 552 "backoffice process %lld still running after %d seconds",
7ed4d03… drh 553 x.idCurrent, runningFor);
6f1c732… drh 554 }
947081a… drh 555 lastWarning = tmNow;
f525b6d… drh 556 warningDelay *= 2;
947081a… drh 557 }
43c2987… drh 558 if( backofficeSleep(1000) ){
43c2987… drh 559 /* The sleep was interrupted by a signal from another thread. */
0fe9da8… mistachkin 560 backofficeTrace("/***** Backoffice Interrupt %d *****/\n", GETPID());
43c2987… drh 561 db_end_transaction(0);
43c2987… drh 562 break;
43c2987… drh 563 }
947081a… drh 564 }
947081a… drh 565 }
947081a… drh 566 return;
947081a… drh 567 }
2d732f4… drh 568
2d732f4… drh 569 /*
71b9f35… drh 570 ** Append to a message to the backoffice log, if the log is open.
71b9f35… drh 571 */
71b9f35… drh 572 void backoffice_log(const char *zFormat, ...){
71b9f35… drh 573 va_list ap;
e05a97a… drh 574 if( backofficeBlob==0 ) return;
e05a97a… drh 575 blob_append_char(backofficeBlob, ' ');
71b9f35… drh 576 va_start(ap, zFormat);
e05a97a… drh 577 blob_vappendf(backofficeBlob, zFormat, ap);
71b9f35… drh 578 va_end(ap);
71b9f35… drh 579 }
71b9f35… drh 580
71b9f35… drh 581 #if !defined(_WIN32)
71b9f35… drh 582 /*
71b9f35… drh 583 ** Capture routine for signals while running backoffice.
71b9f35… drh 584 */
71b9f35… drh 585 static void backoffice_signal_handler(int sig){
e05a97a… drh 586 const char *zSig = 0;
71b9f35… drh 587 if( sig==SIGSEGV ) zSig = "SIGSEGV";
71b9f35… drh 588 if( sig==SIGFPE ) zSig = "SIGFPE";
71b9f35… drh 589 if( sig==SIGABRT ) zSig = "SIGABRT";
71b9f35… drh 590 if( sig==SIGILL ) zSig = "SIGILL";
e05a97a… drh 591 if( zSig==0 ){
e05a97a… drh 592 backoffice_log("signal-%d", sig);
e05a97a… drh 593 }else{
e05a97a… drh 594 backoffice_log("%s", zSig);
e05a97a… drh 595 }
e05a97a… drh 596 fprintf(backofficeFILE, "%s\n", blob_str(backofficeBlob));
e05a97a… drh 597 fflush(backofficeFILE);
71b9f35… drh 598 exit(1);
71b9f35… drh 599 }
71b9f35… drh 600 #endif
71b9f35… drh 601
71b9f35… drh 602 #if !defined(_WIN32)
71b9f35… drh 603 /*
71b9f35… drh 604 ** Convert a struct timeval into an integer number of microseconds
71b9f35… drh 605 */
71b9f35… drh 606 static long long int tvms(struct timeval *p){
71b9f35… drh 607 return ((long long int)p->tv_sec)*1000000 + (long long int)p->tv_usec;
71b9f35… drh 608 }
71b9f35… drh 609 #endif
71b9f35… drh 610
71b9f35… drh 611
71b9f35… drh 612 /*
947081a… drh 613 ** This routine runs to do the backoffice processing. When adding new
947081a… drh 614 ** backoffice processing tasks, add them here.
947081a… drh 615 */
947081a… drh 616 void backoffice_work(void){
2583cae… drh 617 /* Log the backoffice run for testing purposes. For production deployments
2583cae… drh 618 ** the "backoffice-logfile" property should be unset and the following code
2583cae… drh 619 ** should be a no-op. */
c7dca0c… drh 620 const char *zLog = backofficeLogfile;
e05a97a… drh 621 Blob log;
e05a97a… drh 622 int nThis;
e05a97a… drh 623 int nTotal = 0;
71b9f35… drh 624 #if !defined(_WIN32)
71b9f35… drh 625 struct timeval sStart, sEnd;
71b9f35… drh 626 #endif
5911f4b… drh 627 if( zLog==0 ) zLog = db_get("backoffice-logfile",0);
e05a97a… drh 628 if( zLog && zLog[0] && (backofficeFILE = fossil_fopen(zLog,"a"))!=0 ){
e05a97a… drh 629 int i;
75b76ef… drh 630 char *zName = db_get("project-name",0);
71b9f35… drh 631 #if !defined(_WIN32)
71b9f35… drh 632 gettimeofday(&sStart, 0);
71b9f35… drh 633 signal(SIGSEGV, backoffice_signal_handler);
71b9f35… drh 634 signal(SIGABRT, backoffice_signal_handler);
71b9f35… drh 635 signal(SIGFPE, backoffice_signal_handler);
71b9f35… drh 636 signal(SIGILL, backoffice_signal_handler);
71b9f35… drh 637 #endif
75b76ef… drh 638 if( zName==0 ){
75b76ef… drh 639 zName = (char*)file_tail(g.zRepositoryName);
75b76ef… drh 640 if( zName==0 ) zName = "(unnamed)";
75b76ef… drh 641 }else{
75b76ef… drh 642 /* Convert all spaces in the "project-name" into dashes */
75b76ef… drh 643 for(i=0; zName[i]; i++){ if( zName[i]==' ' ) zName[i] = '-'; }
75b76ef… drh 644 }
e05a97a… drh 645 blob_init(&log, 0, 0);
e05a97a… drh 646 backofficeBlob = &log;
e05a97a… drh 647 blob_appendf(&log, "%s %s", db_text(0, "SELECT datetime('now')"), zName);
2583cae… drh 648 }
2583cae… drh 649
2583cae… drh 650 /* Here is where the actual work of the backoffice happens */
cd53239… drh 651 g.zPhase = "backoffice-alerts";
77377e6… drh 652 nThis = alert_backoffice(0);
77377e6… drh 653 if( nThis ){ backoffice_log("%d alerts", nThis); nTotal += nThis; }
cd53239… drh 654 g.zPhase = "backoffice-hooks";
9d8db79… drh 655 nThis = hook_backoffice();
9d8db79… drh 656 if( nThis ){ backoffice_log("%d hooks", nThis); nTotal += nThis; }
cd53239… drh 657 g.zPhase = "backoffice-close";
71b9f35… drh 658
71b9f35… drh 659 /* Close the log */
e05a97a… drh 660 if( backofficeFILE ){
75b76ef… drh 661 if( nTotal || backofficeLogDetail ){
75b76ef… drh 662 if( nTotal==0 ) backoffice_log("no-op");
71b9f35… drh 663 #if !defined(_WIN32)
75b76ef… drh 664 gettimeofday(&sEnd,0);
75b76ef… drh 665 backoffice_log("elapse-time %d us", tvms(&sEnd) - tvms(&sStart));
71b9f35… drh 666 #endif
75b76ef… drh 667 fprintf(backofficeFILE, "%s\n", blob_str(backofficeBlob));
75b76ef… drh 668 }
75b76ef… drh 669 fclose(backofficeFILE);
71b9f35… drh 670 }
4180dc6… drh 671 }
4180dc6… drh 672
4180dc6… drh 673 /*
2931351… drh 674 ** COMMAND: backoffice*
2931351… drh 675 **
ab1023c… drh 676 ** Usage: %fossil backoffice [OPTIONS...] [REPOSITORIES...]
96fc484… drh 677 **
96fc484… drh 678 ** Run backoffice processing on the repositories listed. If no
bc36fdc… danield 679 ** repository is specified, run it on the repository of the local check-out.
96fc484… drh 680 **
96fc484… drh 681 ** This might be done by a cron job or similar to make sure backoffice
1021afc… drh 682 ** processing happens periodically. Or, the --poll option can be used
1021afc… drh 683 ** to run this command as a daemon that will periodically invoke backoffice
8a4b5c4… drh 684 ** on a collection of repositories.
fda6337… drh 685 **
5b4d2df… drh 686 ** If only a single repository is named and --poll is omitted, then the
2f78b2c… danield 687 ** backoffice work is done in-process. But if there are multiple repositories
275da70… danield 688 ** or if --poll is used, a separate sub-process is started for each poll of
fda6337… drh 689 ** each repository.
fda6337… drh 690 **
75b76ef… drh 691 ** Standard options:
e1d8cea… drh 692 **
2e56ef4… km 693 ** --debug Show what this command is doing
e1d8cea… drh 694 **
2e56ef4… km 695 ** --logfile FILE Append a log of backoffice actions onto FILE
e1d8cea… drh 696 **
e1d8cea… drh 697 ** --min N When polling, invoke backoffice at least
e1d8cea… drh 698 ** once every N seconds even if the repository
e1d8cea… drh 699 ** never changes. 0 or negative means disable
e1d8cea… drh 700 ** this feature. Default: 3600 (once per hour).
e1d8cea… drh 701 **
e1d8cea… drh 702 ** --poll N Repeat backoffice calls for repositories that
e0c7e41… brickviking 703 ** change in approximately N-second intervals.
e1d8cea… drh 704 ** N less than 1 turns polling off (the default).
e1d8cea… drh 705 ** Recommended polling interval: 60 seconds.
1021afc… drh 706 **
e1d8cea… drh 707 ** --trace Enable debugging output on stderr
75b76ef… drh 708 **
75b76ef… drh 709 ** Options intended for internal use only which may change or be
8a4b5c4… drh 710 ** discontinued in future releases:
8a4b5c4… drh 711 **
8a4b5c4… drh 712 ** --nodelay Do not queue up or wait for a backoffice job
8a4b5c4… drh 713 ** to complete. If no work is available or if
8a4b5c4… drh 714 ** backoffice has run recently, return immediately.
75b76ef… drh 715 **
75b76ef… drh 716 ** --nolease Always run backoffice, even if there is a lease
8a4b5c4… drh 717 ** conflict. This option implies --nodelay. This
8a4b5c4… drh 718 ** option is added to secondary backoffice commands
4cb50c4… stephan 719 ** that are invoked by the --poll option.
4180dc6… drh 720 */
4180dc6… drh 721 void backoffice_command(void){
1021afc… drh 722 int nPoll;
e1d8cea… drh 723 int nMin;
1021afc… drh 724 const char *zPoll;
1021afc… drh 725 int bDebug = 0;
75b76ef… drh 726 int bNoLease = 0;
1021afc… drh 727 unsigned int nCmd = 0;
2583cae… drh 728 if( find_option("trace",0,0)!=0 ) g.fAnyTrace = 1;
96fc484… drh 729 if( find_option("nodelay",0,0)!=0 ) backofficeNoDelay = 1;
71b9f35… drh 730 backofficeLogfile = find_option("logfile",0,1);
1021afc… drh 731 zPoll = find_option("poll",0,1);
1021afc… drh 732 nPoll = zPoll ? atoi(zPoll) : 0;
e1d8cea… drh 733 zPoll = find_option("min",0,1);
e1d8cea… drh 734 nMin = zPoll ? atoi(zPoll) : 3600;
1021afc… drh 735 bDebug = find_option("debug",0,0)!=0;
75b76ef… drh 736 bNoLease = find_option("nolease",0,0)!=0;
96fc484… drh 737
96fc484… drh 738 /* Silently consume the -R or --repository flag, leaving behind its
96fc484… drh 739 ** argument. This is for legacy compatibility. Older versions of the
96fc484… drh 740 ** backoffice command only ran on a single repository that was specified
96fc484… drh 741 ** using the -R option. */
96fc484… drh 742 (void)find_option("repository","R",0);
96fc484… drh 743
4180dc6… drh 744 verify_all_options();
1021afc… drh 745 if( g.argc>3 || nPoll>0 ){
1021afc… drh 746 /* Either there are multiple repositories named on the command-line
1021afc… drh 747 ** or we are polling. In either case, each backoffice should be run
1021afc… drh 748 ** using a separate sub-process */
96fc484… drh 749 int i;
1021afc… drh 750 time_t iNow = 0;
1021afc… drh 751 time_t ix;
e1d8cea… drh 752 i64 *aLastRun = fossil_malloc( sizeof(i64)*g.argc );
e1d8cea… drh 753 memset(aLastRun, 0, sizeof(i64)*g.argc );
1021afc… drh 754 while( 1 /* exit via "break;" */){
1021afc… drh 755 time_t iNext = time(0);
1021afc… drh 756 for(i=2; i<g.argc; i++){
1021afc… drh 757 Blob cmd;
e1d8cea… drh 758 if( !file_isfile(g.argv[i], ExtFILE) ){
e1d8cea… drh 759 continue; /* Repo no longer exists. Ignore it. */
e1d8cea… drh 760 }
e1d8cea… drh 761 if( iNow
e1d8cea… drh 762 && iNow>file_mtime(g.argv[i], ExtFILE)
e1d8cea… drh 763 && (nMin<=0 || aLastRun[i]+nMin>iNow)
e1d8cea… drh 764 ){
e1d8cea… drh 765 continue; /* Not yet time to run this one */
e1d8cea… drh 766 }
1021afc… drh 767 blob_init(&cmd, 0, 0);
4f83d06… drh 768 blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
1021afc… drh 769 blob_append(&cmd, " backoffice --nodelay", -1);
1021afc… drh 770 if( g.fAnyTrace ){
1021afc… drh 771 blob_append(&cmd, " --trace", -1);
1021afc… drh 772 }
75b76ef… drh 773 if( bDebug ){
75b76ef… drh 774 blob_append(&cmd, " --debug", -1);
75b76ef… drh 775 }
75b76ef… drh 776 if( nPoll>0 ){
75b76ef… drh 777 blob_append(&cmd, " --nolease", -1);
75b76ef… drh 778 }
75b76ef… drh 779 if( backofficeLogfile ){
75b76ef… drh 780 blob_append(&cmd, " --logfile", -1);
4f83d06… drh 781 blob_append_escaped_arg(&cmd, backofficeLogfile, 1);
75b76ef… drh 782 }
4f83d06… drh 783 blob_append_escaped_arg(&cmd, g.argv[i], 1);
1021afc… drh 784 nCmd++;
1021afc… drh 785 if( bDebug ){
1021afc… drh 786 fossil_print("COMMAND[%u]: %s\n", nCmd, blob_str(&cmd));
1021afc… drh 787 }
1021afc… drh 788 fossil_system(blob_str(&cmd));
e1d8cea… drh 789 aLastRun[i] = iNext;
1021afc… drh 790 blob_reset(&cmd);
1021afc… drh 791 }
1021afc… drh 792 if( nPoll<1 ) break;
1021afc… drh 793 iNow = iNext;
1021afc… drh 794 ix = time(0);
1021afc… drh 795 if( ix < iNow+nPoll ){
1021afc… drh 796 sqlite3_int64 nMS = (iNow + nPoll - ix)*1000;
1021afc… drh 797 if( bDebug )fossil_print("SLEEP: %lld\n", nMS);
1021afc… drh 798 sqlite3_sleep((int)nMS);
1021afc… drh 799 }
96fc484… drh 800 }
96fc484… drh 801 }else{
e1d8cea… drh 802 /* Not polling and only one repository named. Backoffice is run
e1d8cea… drh 803 ** once by this process, which then exits */
96fc484… drh 804 if( g.argc==3 ){
96fc484… drh 805 g.zRepositoryOption = g.argv[2];
96fc484… drh 806 g.argc--;
96fc484… drh 807 }
96fc484… drh 808 db_find_and_open_repository(0,0);
e05a97a… drh 809 if( bDebug ){
75b76ef… drh 810 backofficeLogDetail = 1;
75b76ef… drh 811 }
75b76ef… drh 812 if( bNoLease ){
e05a97a… drh 813 backoffice_work();
e05a97a… drh 814 }else{
e05a97a… drh 815 backoffice_thread();
e05a97a… drh 816 }
96fc484… drh 817 }
5542cd4… drh 818 }
5542cd4… drh 819
5542cd4… drh 820 /*
4180dc6… drh 821 ** This is the main interface to backoffice from the rest of the system.
4180dc6… drh 822 ** This routine launches either backoffice_thread() directly or as a
4180dc6… drh 823 ** subprocess.
5542cd4… drh 824 */
4180dc6… drh 825 void backoffice_run_if_needed(void){
4180dc6… drh 826 if( backofficeDb==0 ) return;
4180dc6… drh 827 if( strcmp(backofficeDb,"x")==0 ) return;
4180dc6… drh 828 if( g.db ) return;
4180dc6… drh 829 if( g.repositoryOpen ) return;
2583cae… drh 830 #if defined(_WIN32)
2583cae… drh 831 {
2583cae… drh 832 int i;
2583cae… drh 833 intptr_t x;
2583cae… drh 834 char *argv[4];
2583cae… drh 835 wchar_t *ax[5];
2583cae… drh 836 argv[0] = g.nameOfExe;
2583cae… drh 837 argv[1] = "backoffice";
2583cae… drh 838 argv[2] = "-R";
2583cae… drh 839 argv[3] = backofficeDb;
2583cae… drh 840 ax[4] = 0;
2583cae… drh 841 for(i=0; i<=3; i++) ax[i] = fossil_utf8_to_unicode(argv[i]);
3006826… mistachkin 842 x = _wspawnv(_P_NOWAIT, ax[0], (const wchar_t * const *)ax);
2583cae… drh 843 for(i=0; i<=3; i++) fossil_unicode_free(ax[i]);
0fe9da8… mistachkin 844 backofficeTrace(
864a6f3… mistachkin 845 "/***** Subprocess %d creates backoffice child %lu *****/\n",
864a6f3… mistachkin 846 GETPID(), GetProcessId((HANDLE)x));
2583cae… drh 847 if( x>=0 ) return;
2583cae… drh 848 }
2583cae… drh 849 #else /* unix */
4180dc6… drh 850 {
4180dc6… drh 851 pid_t pid = fork();
4180dc6… drh 852 if( pid>0 ){
4180dc6… drh 853 /* This is the parent in a successful fork(). Return immediately. */
0fe9da8… mistachkin 854 backofficeTrace(
0fe9da8… mistachkin 855 "/***** Subprocess %d creates backoffice child %d *****/\n",
0fe9da8… mistachkin 856 GETPID(), (int)pid);
4180dc6… drh 857 return;
4180dc6… drh 858 }
4180dc6… drh 859 if( pid==0 ){
4180dc6… drh 860 /* This is the child of a successful fork(). Run backoffice. */
15f85cf… drh 861 int i;
2583cae… drh 862 setsid();
c09b251… drh 863 for(i=0; i<=2; i++){
c09b251… drh 864 close(i);
c09b251… drh 865 open("/dev/null", O_RDWR);
c09b251… drh 866 }
c09b251… drh 867 for(i=3; i<100; i++){ close(i); }
458ced3… drh 868 g.fDebug = 0;
458ced3… drh 869 g.httpIn = 0;
458ced3… drh 870 g.httpOut = 0;
4180dc6… drh 871 db_open_repository(backofficeDb);
4180dc6… drh 872 backofficeDb = "x";
4180dc6… drh 873 backoffice_thread();
4180dc6… drh 874 db_close(1);
0fe9da8… mistachkin 875 backofficeTrace("/***** Backoffice Child %d exits *****/\n", GETPID());
4180dc6… drh 876 exit(0);
4180dc6… drh 877 }
864a6f3… mistachkin 878 fossil_warning("backoffice process %d fork failed, errno %d", GETPID(),
864a6f3… mistachkin 879 errno);
4180dc6… drh 880 }
4180dc6… drh 881 #endif
4180dc6… drh 882 /* Fork() failed or is unavailable. Run backoffice in this process, but
4180dc6… drh 883 ** do so with the no-delay setting.
4180dc6… drh 884 */
4180dc6… drh 885 backofficeNoDelay = 1;
4180dc6… drh 886 db_open_repository(backofficeDb);
4180dc6… drh 887 backofficeDb = "x";
4180dc6… drh 888 backoffice_thread();
4180dc6… drh 889 db_close(1);
947081a… drh 890 }

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button