Changeset: 583ffdb030f0 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/583ffdb030f0 Branch: multi-cachelock Log Message:
Merge with default. diffs (truncated from 452 to 300 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -785,3 +785,4 @@ 47675351fec22d5d5dc81eec03dfa08f505afc99 47675351fec22d5d5dc81eec03dfa08f505afc99 Sep2022_release 44e45c9a451f6afd933773094ec25723f713d3be Jan2022_23 44e45c9a451f6afd933773094ec25723f713d3be Jan2022_SP5_release +43d4a717410d6f6692a16a878640fc7e0f248725 Jan2022_25 diff --git a/clients/examples/C/testcondvar.c b/clients/examples/C/testcondvar.c --- a/clients/examples/C/testcondvar.c +++ b/clients/examples/C/testcondvar.c @@ -16,7 +16,12 @@ volatile int timeout = 100; // set this to 0 during interactive debugging -/* global state protected by a lock: */ +/* global state protected by a lock. + * + * Every worker thread has a number of permits and a number of ticks. + * It sleeps on the condition variable, whenever it wakes it will + * try to convert one permit into a tick, that is, permit-- and tick++. + */ MT_Lock lock = MT_LOCK_INITIALIZER(lock); MT_Cond condvar = MT_COND_INITIALIZER(the_condvar); @@ -28,7 +33,15 @@ struct state { bool terminated; } states[NN] = { {0} }; - +/* + * The main thread holds the lock so it can manipulate and verify the permits + * and ticks. It uses this function to temporarily release the lock so the + * workers get a chance to do their work. We give them a 100ms, which should be + * plenty. + * + * If we cannot retake the lock after that interval we assume a worker thread + * has gone astray while holding the lock. + */ static void let_run(void) { @@ -36,16 +49,17 @@ let_run(void) MT_sleep_ms(100); + // try to retake the lock. Make a few attempts before giving up. int attempts = 0; while (!MT_lock_try(&lock)) { if (timeout > 0 && ++attempts > timeout) { fprintf(stderr, "Can't get hold of the lock after %d attempts\n", attempts); + fprintf(stderr, "If this is because you're running this program in a debugger,\n"); + fprintf(stderr, "try setting the timeout variable to 0.\n"); abort(); } MT_sleep_ms(10); } - - fprintf(stderr, "\n"); } @@ -54,9 +68,10 @@ worker(void *arg) { struct state *st = arg; int id = (int)(st - &states[0]); - fprintf(stderr, "worker %d starting\n", id); + fprintf(stderr, "worker %d started, waiting to acquire lock\n", id); MT_lock_set(&lock); + fprintf(stderr, "worker %d acquired lock\n", id); while (1) { if (st->terminate) { fprintf(stderr, "worker %d terminating\n", id); @@ -67,7 +82,7 @@ worker(void *arg) st->ticks++; st->permits--; } - fprintf(stderr, "worker %d waiting\n", id); + fprintf(stderr, "worker %d waiting on condvar\n", id); MT_cond_wait(&condvar, &lock); fprintf(stderr, "worker %d woke up\n", id); } @@ -76,16 +91,6 @@ worker(void *arg) } -static void clear(void) -{ - for (int i = 0; i < NN; i++) { - struct state *st = &states[i]; - st->permits = 0; - st->ticks = 0; - } -} - - static void check_impl(int line, int expected_sum_ticks, int expected_max_ticks, int expected_sum_permits) { @@ -101,17 +106,26 @@ check_impl(int line, int expected_sum_ti max_ticks = ticks; } + fprintf(stderr, "On line %d: (sum_ticks, max_ticks, sum_permits) = (%d, %d, %d)\n", + line, + sum_ticks, max_ticks, sum_permits); + bool good = true; good &= (sum_ticks == expected_sum_ticks); - good &= (max_ticks == expected_max_ticks); + if (expected_max_ticks >= 0) + good &= (max_ticks == expected_max_ticks); good &= (sum_permits == expected_sum_permits); if (good) return; - fprintf(stderr, "\nOn line %d:\n", line); - fprintf(stderr, "Expect sum ticks to be %d, is %d\n", expected_sum_ticks, sum_ticks); - fprintf(stderr, "Expect max ticks to be %d, is %d\n", expected_max_ticks, max_ticks); - fprintf(stderr, "Expect sum permits to be %d, is %d\n", expected_sum_permits, sum_permits); + if (expected_max_ticks >= 0) { + fprintf(stderr, "MISMATCH: expected (%d, %d, %d)\n", + expected_sum_ticks, expected_max_ticks, expected_sum_permits); + } else { + fprintf(stderr, "MISMATCH: expected (%d, ?, %d)\n", + expected_sum_ticks, expected_sum_permits); + } + for (int i = 0; i < NN; i++) { fprintf(stderr, "worker %d: ticks=%d permits=%d\n", i, states[i].ticks, states[i].permits); } @@ -125,46 +139,54 @@ main(void) { MT_thread_init(); + // All code in this function runs while we hold the lock. + // From time to time we call let_run() to allow the worker threads to obtain it. MT_lock_set(&lock); + + fprintf(stderr, "-- Initially, everything is zero\n"); check(0, 0, 0); + fprintf(stderr, "\n-- Starting the worker threads\n"); for (int i = 0; i < NN; i++) { struct state *st = &states[i]; char name[MT_NAME_LEN]; snprintf(name, sizeof(name), "worker%d", i); MT_create_thread(&st->id, worker, st, MT_THR_JOINABLE, name); } - check(0, 0, 0); + MT_sleep_ms(100); + fprintf(stderr, "\n-- Now allow the workers to take the lock, they should enter their main loop\n"); let_run(); check(0, 0, 0); - // give them all a permit and broadcast on the condvar. they should all run + fprintf(stderr, "\n-- All threads get a permit but nothing happens because we haven't touched the condvar\n"); for (int i = 0; i < NN; i++) states[i].permits = 1; let_run(); - // haven't notified them yet: - check(0, 0, 3); + check(0, 0, NN); + + fprintf(stderr, "\n-- Now we broadcast on the condvar. All should wake\n"); MT_cond_broadcast(&condvar); let_run(); - check(3, 1, 0); + check(NN, 1, 0); + + fprintf(stderr, "\n-- Now we give each of them %d permits\n", NN); + for (int i = 0; i < NN; i++) { + states[i].ticks = 0; + states[i].permits = NN; + } + check(0, 0, NN * NN); - // when using signal, we need to trigger them three times - clear(); - for (int i = 0; i < NN; i++) - states[i].permits = 1; - let_run(); - check(0, 0, 3); - MT_cond_signal(&condvar); - let_run(); - check(1, 1, 2); - MT_cond_signal(&condvar); - let_run(); - check(2, 1, 1); - MT_cond_signal(&condvar); - let_run(); - check(3, 1, 0); + // Note: counting from 1 instead of 0 + for (int i = 1; i <= NN; i++) { + fprintf(stderr, "\n-- [%d] Signal one, don't know which one it will be\n", i); + MT_cond_signal(&condvar); + let_run(); + check(i, -1, NN * NN - i); + } + + fprintf(stderr, "\n-- Telling them all to quit\n"); for (int i = 0; i < NN; i++) { states[i].terminate = true; } @@ -172,12 +194,11 @@ main(void) let_run(); for (int i = 0; i < NN; i++) { - fprintf(stderr, "joining worker %d\n", i); + fprintf(stderr, "-- Joining worker %d\n", i); MT_join_thread(states[i].id); + fprintf(stderr, "-- Joined worker %d\n", i); } - fprintf(stderr, "joined all, exiting\n"); + fprintf(stderr, "\n-- Joined all, exiting\n"); - (void)worker; - (void)let_run; return 0; } diff --git a/gdk/gdk_bat.c b/gdk/gdk_bat.c --- a/gdk/gdk_bat.c +++ b/gdk/gdk_bat.c @@ -2198,9 +2198,14 @@ backup_new(Heap *hp, bool lock) char *batpath, *bakpath; struct stat st; + char *bak_filename = NULL; + if ((bak_filename = strrchr(hp->filename, DIR_SEP)) != NULL) + bak_filename++; + else + bak_filename = hp->filename; /* check for an existing X.new in BATDIR, BAKDIR and SUBDIR */ batpath = GDKfilepath(hp->farmid, BATDIR, hp->filename, "new"); - bakpath = GDKfilepath(hp->farmid, BAKDIR, hp->filename, "new"); + bakpath = GDKfilepath(hp->farmid, BAKDIR, bak_filename, "new"); if (batpath != NULL && bakpath != NULL) { /* file actions here interact with the global commits */ if (lock) diff --git a/geom/lib/libgeom.c b/geom/lib/libgeom.c --- a/geom/lib/libgeom.c +++ b/geom/lib/libgeom.c @@ -23,7 +23,7 @@ geomerror(_In_z_ _Printf_format_string_ char err[256]; va_start(va, fmt); vsnprintf(err, sizeof(err), fmt, va); - GDKtracer_log(__FILE__, __func__, __LINE__, M_CRITICAL, + GDKtracer_log(__FILE__, __func__, __LINE__, M_ERROR, GDK, NULL, "%s", err); va_end(va); } diff --git a/sql/jdbc/tests/Tests/OnClientTester.SQL.py b/sql/jdbc/tests/Tests/OnClientTester.SQL.py --- a/sql/jdbc/tests/Tests/OnClientTester.SQL.py +++ b/sql/jdbc/tests/Tests/OnClientTester.SQL.py @@ -20,11 +20,3 @@ try: except CalledProcessError as e: raise SystemExit(e.stderr) - - -##!/bin/sh -# -#URL="jdbc:monetdb://${HOST}:${MAPIPORT}/${TSTDB}?user=monetdb&password=monetdb${JDBC_EXTRA_ARGS}" -#TST=$1 -# -#java ${TST} "${URL}" diff --git a/sql/test/concurrent/Tests/All b/sql/test/concurrent/Tests/All --- a/sql/test/concurrent/Tests/All +++ b/sql/test/concurrent/Tests/All @@ -4,3 +4,4 @@ segments-corruption read-segment-after-free smart-segment-merge many-concurrent-client-connections +truncate-insert-flood diff --git a/sql/test/concurrent/Tests/truncate-insert-flood.py b/sql/test/concurrent/Tests/truncate-insert-flood.py new file mode 100644 --- /dev/null +++ b/sql/test/concurrent/Tests/truncate-insert-flood.py @@ -0,0 +1,66 @@ +import sys, os, tempfile, pymonetdb + +try: + from MonetDBtesting import process +except ImportError: + import process + +from concurrent.futures import ThreadPoolExecutor + +nr_clients = 16 + +with tempfile.TemporaryDirectory() as dbfarm: + os.mkdir(os.path.join(dbfarm, 'db')) + + with open(os.path.join(dbfarm, 'errout'), mode='a+') as errout: + with process.server( + dbname='db', + dbfarm=os.path.join(dbfarm, 'db'), _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org