Variable WRITE_WORKLOAD_PHPConst
WRITE_WORKLOAD_PHP: "\nuse Drupal\\Core\\DrupalKernel;\nuse Drupal\\Core\\Site\\Settings;\nuse Drupal\\file\\Entity\\File;\nuse Drupal\\node\\Entity\\Node;\nuse Drupal\\node\\Entity\\NodeType;\nuse Drupal\\user\\Entity\\User;\nuse Symfony\\Component\\HttpFoundation\\Request;\n\n// __CFW_FIBER_SHIM__\n// __CFW_HOST_HELPERS__\nchdir('/drupal');\n\n$opt = json_decode(__CFW_PAYLOAD__, true);\n$out = ['ok' => false, 'op' => $opt['op']];\n\n$_SERVER['HTTP_HOST'] = 'localhost';\n$_SERVER['SERVER_NAME'] = 'localhost';\n$_SERVER['SERVER_PORT'] = '80';\n$_SERVER['REQUEST_URI'] = '/';\n$_SERVER['REQUEST_METHOD'] = 'GET';\n$_SERVER['SCRIPT_NAME'] = '/index.php';\n$_SERVER['SCRIPT_FILENAME'] = '/drupal/index.php';\n$_SERVER['PHP_SELF'] = '/index.php';\n$_SERVER['DOCUMENT_ROOT'] = '/drupal';\n$_SERVER['REMOTE_ADDR'] = '127.0.0.1';\n$_SERVER['SERVER_SOFTWARE'] = 'workerd';\n$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';\n\ntry {\n\tif (!isset($GLOBALS['__pw_autoloader']) || !is_object($GLOBALS['__pw_autoloader'])) {\n\t\t$GLOBALS['__pw_autoloader'] = require '/drupal/autoload.php';\n\t}\n\t$autoloader = $GLOBALS['__pw_autoloader'];\n\tif (!isset($GLOBALS['__pw_kernel'])) {\n\t\t$boot = Request::create('/', 'GET');\n\t\t$kernel = new DrupalKernel('prod', $autoloader);\n\t\tDrupalKernel::bootEnvironment();\n\t\t$sitePath = DrupalKernel::findSitePath($boot);\n\t\t$kernel->setSitePath($sitePath);\n\t\tSettings::initialize('/drupal', $sitePath, $autoloader);\n\t\t$kernel->boot();\n\t\t$GLOBALS['__pw_kernel'] = $kernel;\n\t\t$out['bootedKernel'] = 1;\n\t}\n\n\tif (!defined('SAVED_NEW')) {\n\t\trequire_once '/drupal/core/includes/common.inc';\n\t}\n\n\tif (empty($GLOBALS['__cfw_schema_repaired'])) {\n\t\t$GLOBALS['__cfw_schema_repaired'] = true;\n\t\t// __CFW_SCHEMA_REPAIR__\n\t}\n\n\t$db = Drupal::database();\n\t// the driver's own counters, which the host tally cannot see: a speculative replay re-sends\n\t// buffered statements to resolve an insert id, and that is CPU the rows meter never charges\n\t$counter = function ($method) use ($db) {\n\t\treturn method_exists($db, $method) ? (int) $db->$method() : -1;\n\t};\n\t$before = [\n\t\t'statements' => $counter('statementCount'),\n\t\t'transactions' => $counter('transactionCount'),\n\t\t'speculative' => $counter('speculativeCount'),\n\t\t'replayed' => $counter('replayedStatementCount'),\n\t];\n\n\t$seq = (int) $opt['seq'];\n\t$nid = (int) $opt['nid'];\n\t$previousAccount = Drupal::currentUser()->getAccount();\n\t$admin = User::load(1);\n\tif ($admin !== null) {\n\t\tDrupal::currentUser()->setAccount($admin);\n\t}\n\n\tswitch ($opt['op']) {\n\t\tcase 'node-create':\n\t\t\t$types = array_keys(NodeType::loadMultiple());\n\t\t\t$type = in_array('page', $types, true) ? 'page' : $types[0] ?? null;\n\t\t\tif ($type === null) {\n\t\t\t\tthrow new RuntimeException('no node type exists in this site');\n\t\t\t}\n\t\t\t$node = Node::create([\n\t\t\t\t'type' => $type,\n\t\t\t\t'title' => 'Amplification ' . $seq,\n\t\t\t\t'uid' => 1,\n\t\t\t\t'status' => 1,\n\t\t\t]);\n\t\t\t$node->save();\n\t\t\t$out['id'] = (int) $node->id();\n\t\t\t$out['vid'] = (int) $node->getRevisionId();\n\t\t\tbreak;\n\n\t\tcase 'node-revision':\n\t\t\t$node = Node::load($nid);\n\t\t\tif ($node === null) {\n\t\t\t\tthrow new RuntimeException('no node ' . $nid . ' to revise');\n\t\t\t}\n\t\t\t// explicit rather than relying on the content type default, which is configuration\n\t\t\t$node->setNewRevision(true);\n\t\t\t$node->setRevisionLogMessage('amplification ' . $seq);\n\t\t\t$node->setRevisionCreationTime((int) Drupal::time()->getRequestTime());\n\t\t\t$node->setRevisionUserId(1);\n\t\t\t$node->setTitle('Amplification revised ' . $seq);\n\t\t\t$node->save();\n\t\t\t$out['id'] = (int) $node->id();\n\t\t\t$out['vid'] = (int) $node->getRevisionId();\n\t\t\tbreak;\n\n\t\tcase 'user-create':\n\t\t\t$account = User::create(['name' => 'amp' . $seq]);\n\t\t\t$account->setEmail('amp' . $seq . '@example.invalid');\n\t\t\t$account->setPassword('cfw-Amp-' . $seq . '-pass');\n\t\t\t$account->activate();\n\t\t\t$account->save();\n\t\t\t$out['id'] = (int) $account->id();\n\t\t\tbreak;\n\n\t\tcase 'file-create':\n\t\t\t// the ROW, not the bytes: a real upload also writes the stream, and that lands in MEMFS and\n\t\t\t// the R2 mirror rather than in Durable Object SQL, so it is a different meter\n\t\t\t$file = File::create([\n\t\t\t\t'uri' => 'public://amplification-' . $seq . '.txt',\n\t\t\t\t'filename' => 'amplification-' . $seq . '.txt',\n\t\t\t\t'filemime' => 'text/plain',\n\t\t\t\t'filesize' => 11,\n\t\t\t\t'status' => 1,\n\t\t\t\t'uid' => 1,\n\t\t\t]);\n\t\t\t$file->save();\n\t\t\t$out['id'] = (int) $file->id();\n\t\t\tbreak;\n\n\t\tcase 'alias-create':\n\t\t\t$alias = Drupal::entityTypeManager()\n\t\t\t\t->getStorage('path_alias')\n\t\t\t\t->create([\n\t\t\t\t\t'path' => '/node/' . ($nid > 0 ? $nid : 1),\n\t\t\t\t\t'alias' => '/amplification-' . $seq,\n\t\t\t\t\t'langcode' => 'en',\n\t\t\t\t]);\n\t\t\t$alias->save();\n\t\t\t$out['id'] = (int) $alias->id();\n\t\t\tbreak;\n\n\t\tcase 'txn-autoinc':\n\t\tcase 'txn-rowid':\n\t\t\t// THE A/B. Both tables are created by the caller and differ only in the keyword, so what this\n\t\t\t// measures is whether predictBufferedInsertId() could answer -- it refuses AUTOINCREMENT,\n\t\t\t// because that table's next id comes from sqlite_sequence rather than from max(rowid) + 1,\n\t\t\t// and the fallback replays the whole buffer through the host\n\t\t\t$table = $opt['op'] === 'txn-autoinc' ? 'amp_txn_auto' : 'amp_txn_rowid';\n\t\t\t$txn = $db->startTransaction();\n\t\t\t$db->query('INSERT INTO {' . $table . '} (v) VALUES (:v)', [':v' => 'row ' . $seq]);\n\t\t\t$out['id'] = (int) $db->lastInsertId();\n\t\t\tunset($txn);\n\t\t\t$out['table'] = $table;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow new RuntimeException('unknown workload ' . $opt['op']);\n\t}\n\n\t$out['driver'] = [\n\t\t'statements' => $counter('statementCount') - $before['statements'],\n\t\t'transactions' => $counter('transactionCount') - $before['transactions'],\n\t\t'speculative' => $counter('speculativeCount') - $before['speculative'],\n\t\t'replayed' => $counter('replayedStatementCount') - $before['replayed'],\n\t\t// WHY each replay happened, not just how many. Two mechanisms were proposed for these on a\n\t\t// count alone and neither moved it; a reason cannot be guessed at a third time\n\t\t'refusals' => method_exists($db, 'predictionRefusals') ? $db->predictionRefusals() : [],\n\t];\n\t$out['ok'] = $out['id'] > 0;\n} catch (Throwable $e) {\n\t$out['error'] = get_class($e) . ': ' . $e->getMessage();\n\t$out['trace'] = substr($e->getTraceAsString(), 0, 900);\n} finally {\n\tif (isset($previousAccount)) {\n\t\ttry {\n\t\t\tDrupal::currentUser()->setAccount($previousAccount);\n\t\t} catch (Throwable $e2) {\n\t\t}\n\t}\n}\n\necho json_encode($out);\n"