@@ -132,6 +132,8 @@ thread_runner_main(void *arg)
132
132
runner->_errno = runner->run ();
133
133
} catch (WorkgenException &wge) {
134
134
runner->_exception = wge;
135
+ std::cerr << " Exception in runner->run(): " << wge._str << std::endl;
136
+ ASSERT (false );
135
137
}
136
138
return (nullptr );
137
139
}
@@ -148,6 +150,7 @@ thread_workload(void *arg)
148
150
runner->increment_timestamp (connection);
149
151
} catch (WorkgenException &wge) {
150
152
std::cerr << " Exception while incrementing timestamp: " << wge._str << std::endl;
153
+ ASSERT (false );
151
154
}
152
155
153
156
return (nullptr );
@@ -164,6 +167,7 @@ thread_idle_table_cycle_workload(void *arg)
164
167
runner->start_table_idle_cycle (connection);
165
168
} catch (WorkgenException &wge) {
166
169
std::cerr << " Exception while create/drop tables: " << wge._str << std::endl;
170
+ ASSERT (false );
167
171
}
168
172
169
173
return (nullptr );
@@ -180,6 +184,7 @@ thread_tables_create_workload(void *arg)
180
184
runner->start_tables_create (connection);
181
185
} catch (WorkgenException &wge) {
182
186
std::cerr << " Exception while creating tables: " << wge._str << std::endl;
187
+ ASSERT (false );
183
188
}
184
189
185
190
return (nullptr );
@@ -196,6 +201,7 @@ thread_tables_drop_workload(void *arg)
196
201
runner->start_tables_drop (connection);
197
202
} catch (WorkgenException &wge) {
198
203
std::cerr << " Exception while dropping tables: " << wge._str << std::endl;
204
+ ASSERT (false );
199
205
}
200
206
201
207
return (nullptr );
@@ -353,42 +359,104 @@ gen_random_table_name(char *name, workgen_random_state volatile *rand_state)
353
359
* fails.
354
360
*/
355
361
int
356
- WorkloadRunner::create_table (WT_SESSION *session, const std::string &config, const std::string &uri,
357
- const std::string &mirror_uri , const bool is_base )
362
+ WorkloadRunner::create_table (
363
+ WT_SESSION *session, const std::string &config , const std::string &uri, bool mirror_enabled )
358
364
{
359
- // Check if a table with this name already exists. Return if it does. Use a shared lock to
360
- // read the dynamic table structure.
365
+ const std::string mirror_uri (mirror_enabled ? uri + _workload->options .mirror_suffix : " " );
366
+
367
+ // Return if a table with the same name already exists. If mirror is enabled, make sure it does
368
+ // not exist either.
361
369
ContextInternal *icontext = _workload->_context ->_internal ;
362
370
{
371
+ // Use a shared lock to read the dynamic table structure.
363
372
const std::shared_lock lock (*icontext->_dyn_mutex );
364
373
if (icontext->_tint .count (uri) > 0 || icontext->_dyn_tint .count (uri) > 0 )
365
374
return EEXIST;
375
+ if (mirror_enabled &&
376
+ (icontext->_tint .count (mirror_uri) > 0 || icontext->_dyn_tint .count (mirror_uri) > 0 ))
377
+ return EEXIST;
366
378
}
367
379
368
- // Create the table.
369
- WT_DECL_RET;
370
- if ((ret = session->create (session, uri.c_str (), config.c_str ())) != 0 ) {
371
- if (ret != EBUSY)
372
- THROW (" Failed to create table '" << uri << " '." );
380
+ /*
381
+ * When mirror is enabled, create the mirror first and then the base. If we create the base
382
+ * first, threads may start working on the base while the mirror is not fully created.
383
+ *
384
+ * The config has to be updated with the following information:
385
+ * - The name of the table's mirror if mirroring is enabled.
386
+ * - If this table is a base table or a mirror.
387
+ *
388
+ * See below an example when creating the table 'a' with mirror enabled:
389
+ * - Configuration expected for the mirror:
390
+ * app_metadata="workgen_dynamic_table=true,workgen_table_mirror=table:a,workgen_base_table=false"
391
+ * - Configuration expected for the base:
392
+ * app_metadata="workgen_dynamic_table=true,workgen_table_mirror=table:a_mirror,workgen_base_table=true"
393
+ *
394
+ * Without mirror enabled:
395
+ * app_metadata="workgen_dynamic_table=true,workgen_base_table=true"
396
+ *
397
+ */
398
+ std::string mirror_config;
399
+ if (mirror_enabled) {
400
+ mirror_config = config + " ," + MIRROR_TABLE_APP_METADATA + uri + " ," +
401
+ BASE_TABLE_APP_METADATA + " false\" " ;
402
+ int ret = session->create (session, mirror_uri.c_str (), mirror_config.c_str ());
403
+ if (ret != 0 ) {
404
+ VERBOSE (*_workload, " Failed to create mirror table '" << mirror_uri << " '" );
405
+ return ret;
406
+ }
407
+ // This will be used when creating the base table.
408
+ mirror_config = MIRROR_TABLE_APP_METADATA + mirror_uri + " ," ;
409
+ }
410
+
411
+ // If mirror is enabled, we don't want to fail when creating the base. Getting spurious EBUSY
412
+ // errors is ok though, retry in that case.
413
+ const std::string base_config (
414
+ config + " ," + mirror_config + BASE_TABLE_APP_METADATA + " true\" " );
415
+ int ret, retries = 0 ;
416
+
417
+ do {
418
+ ret = session->create (session, uri.c_str (), base_config.c_str ());
419
+ } while (ret != 0 && ret == EBUSY && mirror_enabled && ++retries < TABLE_MAX_RETRIES);
420
+
421
+ if (ret != 0 ) {
422
+ const std::string err_msg (" Failed to create table '" + uri + " '" );
423
+ VERBOSE (*_workload, err_msg);
424
+ // Fail if we have failed at creating the base of a mirror.
425
+ if (mirror_enabled)
426
+ THROW_ERRNO (ret, err_msg);
373
427
return ret;
374
428
}
375
429
376
- // The data structures for the dynamic table set are protected by a mutex.
430
+ // All the required tables have been created, update the data structures for the dynamic tables
431
+ // which are protected by a mutex.
377
432
{
378
433
const std::lock_guard<std::shared_mutex> lock (*icontext->_dyn_mutex );
379
-
380
- // Add the table into the list of dynamic set.
381
- tint_t tint = icontext->_dyn_tint_last ;
382
- icontext->_dyn_tint [uri] = tint;
383
- icontext->_dyn_table_names [tint] = uri;
384
- icontext->_dyn_table_runtime [tint] = TableRuntime (is_base, mirror_uri);
385
- ++icontext->_dyn_tint_last ;
386
- VERBOSE (*_workload, " Created table and added to the dynamic set: " << uri);
434
+ update_dyn_struct_locked (uri, true , mirror_uri);
435
+ if (mirror_enabled)
436
+ update_dyn_struct_locked (mirror_uri, false , uri);
387
437
}
388
438
389
439
return 0 ;
390
440
}
391
441
442
+ /*
443
+ * Update the structures dedicated to tables that can be created or removed during the workload. The
444
+ * caller should hold the mutex that protects those structures.
445
+ */
446
+ void
447
+ WorkloadRunner::update_dyn_struct_locked (
448
+ const std::string &uri, bool is_base, const std::string &mirror_uri)
449
+ {
450
+ ContextInternal *icontext = _workload->_context ->_internal ;
451
+
452
+ // This should be safe as we are supposed to be under a lock.
453
+ tint_t tint = icontext->_dyn_tint_last ++;
454
+ icontext->_dyn_tint [uri] = tint;
455
+ icontext->_dyn_table_names [tint] = uri;
456
+ icontext->_dyn_table_runtime [tint] = TableRuntime (is_base, mirror_uri);
457
+ VERBOSE (*_workload, " Created table and added to the dynamic set: " << uri);
458
+ }
459
+
392
460
/*
393
461
* This function creates one or more tables at regular intervals, where the interval length and
394
462
* number of tables are specified in the workload options. It also monitors the database size and
@@ -415,25 +483,6 @@ WorkloadRunner::start_tables_create(WT_CONNECTION *conn)
415
483
creating = db_size < _workload->options .create_target ;
416
484
}
417
485
418
- std::string uri;
419
- std::string mirror_uri = std::string ();
420
- int creates, retries, status;
421
- char rand_chars[DYNAMIC_TABLE_LEN];
422
-
423
- /*
424
- * Add app_metadata to the config to indicate the table was created dynamically (can be selected
425
- * for random deletion), the name of the table's mirror if mirroring is enabled, and if this
426
- * table is a base table or a mirror. We want these settings to persist over restarts.
427
- */
428
- std::string base_config =
429
- " key_format=S,value_format=S,app_metadata=\" " + DYN_TABLE_APP_METADATA;
430
- if (_workload->options .mirror_tables ) {
431
- base_config += " ," + MIRROR_TABLE_APP_METADATA;
432
- } else {
433
- base_config += " ," + BASE_TABLE_APP_METADATA + " true\" " ;
434
- }
435
- std::string config = base_config;
436
-
437
486
while (!stopping) {
438
487
/*
439
488
* When managing the database size: If we are creating tables, continue until we reach the
@@ -465,40 +514,27 @@ WorkloadRunner::start_tables_create(WT_CONNECTION *conn)
465
514
continue ;
466
515
}
467
516
468
- retries = 0 ;
469
- creates = 0 ;
470
- while (creates < _workload->options .create_count ) {
517
+ // Add app_metadata to the config to indicate the table was created dynamically which means
518
+ // it can be selected for random deletion. We want this information to persist over restart.
519
+ const std::string config (
520
+ " key_format=S,value_format=S,app_metadata=\" " + DYN_TABLE_APP_METADATA);
471
521
522
+ int creates = 0 , retries = 0 ;
523
+ while (
524
+ !stopping && creates < _workload->options .create_count && retries < TABLE_MAX_RETRIES) {
472
525
// Generate a table name from the user specified prefix and a random alphanumeric
473
526
// sequence.
527
+ char rand_chars[DYNAMIC_TABLE_LEN];
474
528
gen_random_table_name (rand_chars, _rand_state);
475
- uri = " table:" ;
476
- uri += _workload->options .create_prefix ;
477
- uri += rand_chars;
478
-
479
- if (_workload->options .mirror_tables ) {
480
- // The mirror table name is the table name with the user specified suffix.
481
- mirror_uri = uri + _workload->options .mirror_suffix ;
482
- config = base_config + mirror_uri + " ," + BASE_TABLE_APP_METADATA + " true\" " ;
483
- }
529
+ const std::string uri (" table:" + _workload->options .create_prefix + rand_chars);
484
530
485
- // Create the table. Simply continue on failure.
486
- if (create_table (session, config, uri, mirror_uri, true ) == 0 ) {
487
- VERBOSE (*_workload, " Created base table '" << uri << " '" );
488
- if (_workload->options .mirror_tables ) {
489
- // Create the mirror. Retry on failure and throw an exception after
490
- // making too many retry attempts.
491
- config = base_config + uri + " ," + BASE_TABLE_APP_METADATA + " false\" " ;
492
- do
493
- status = create_table (session, config, mirror_uri, uri, false );
494
- while (status == EBUSY && ++retries < TABLE_MAX_RETRIES);
495
- if (status != 0 )
496
- THROW_ERRNO (
497
- status, " Failed to create mirror table '" << mirror_uri << " '." );
498
- VERBOSE (*_workload, " Created mirror table '" << mirror_uri << " '" );
499
- }
531
+ // Create the table and its mirror if enabled.
532
+ int ret = create_table (session, config, uri, _workload->options .mirror_tables );
533
+ ASSERT (ret == 0 || ret == EBUSY || ret == EEXIST);
534
+ if (ret == 0 )
500
535
++creates;
501
- }
536
+ else
537
+ ++retries;
502
538
}
503
539
sleep (_workload->options .create_interval );
504
540
}
@@ -709,6 +745,8 @@ monitor_main(void *arg)
709
745
monitor->_errno = monitor->run ();
710
746
} catch (WorkgenException &wge) {
711
747
monitor->_exception = wge;
748
+ std::cerr << " Exception in monitor->run(): " << wge._str << std::endl;
749
+ ASSERT (false );
712
750
}
713
751
return (nullptr );
714
752
}
@@ -1478,7 +1516,7 @@ ThreadRunner::op_get_table(Operation *op) const
1478
1516
1479
1517
std::string uri = op->_tables [_number];
1480
1518
tint_t tint = 0 ;
1481
- if (uri != std::string ()) {
1519
+ if (!uri. empty ()) {
1482
1520
const std::shared_lock lock (*_icontext->_dyn_mutex );
1483
1521
tint = _icontext->_dyn_tint [uri];
1484
1522
}
@@ -1612,13 +1650,12 @@ ThreadRunner::op_run_setup(Operation *op)
1612
1650
std::advance (itr, random_value () % num_tables);
1613
1651
1614
1652
if (_icontext->_dyn_table_runtime [itr->second ]._is_base &&
1615
- !_icontext->_dyn_table_runtime [itr->second ]._pending_delete ) {
1653
+ !_icontext->_dyn_table_runtime [itr->second ]._pending_delete )
1616
1654
break ;
1617
- }
1618
1655
}
1619
- if (num_tables == 0 || retries >= TABLE_MAX_RETRIES) { // Try again next time.
1656
+ // Try again next time.
1657
+ if (num_tables == 0 || retries >= TABLE_MAX_RETRIES)
1620
1658
return 0 ;
1621
- }
1622
1659
1623
1660
std::string op_uri = itr->first ; // Get the table name.
1624
1661
tint_t op_tint = itr->second ; // Get the tint.
0 commit comments