Merge pull request #102 from Shadowss/lietuvis10-patch-3

Update Database.php
This commit is contained in:
Catalin Novgorodschi
2025-10-28 08:14:18 +02:00
committed by GitHub
+135
View File
@@ -6995,6 +6995,141 @@ References: User ID/Message ID, Mode
return true;
}
/*** Build/rebuild the croppers precompute table from wdata. */
public function TotalCroppers(): int {
$TBP = defined('TB_PREFIX') ? TB_PREFIX : 's1_';
$WDATA = $TBP . 'wdata';
$res = mysqli_query($this->dblink, "SELECT COUNT(*) AS cnt FROM `$WDATA` WHERE fieldtype IN (1,6)");
if (!$res) {
throw new Exception('Count query failed: ' . mysqli_error($this->dblink));
}
$row = mysqli_fetch_assoc($res);
return (int)($row['cnt'] ?? 0);
}
public function populateCroppers(int $countTotal = 0, bool $truncateFirst = false, int $batch = 20000, ?callable $reporter = null ): array {
@set_time_limit(0);
@ini_set('memory_limit', '1G');
$TBP = defined('TB_PREFIX') ? TB_PREFIX : 's1_';
$CROP_TABLE = $TBP . 'croppers';
$WDATA = $TBP . 'wdata';
// Count once if caller didn't
if ($countTotal <= 0) {
$row = mysqli_fetch_assoc(mysqli_query($this->dblink,
"SELECT COUNT(*) cnt FROM `$WDATA` WHERE fieldtype IN (1,6)"));
$countTotal = (int)($row['cnt'] ?? 0);
}
if ($truncateFirst) {
if (!mysqli_query($this->dblink, "TRUNCATE TABLE `$CROP_TABLE`")) {
return ['ok'=>false,'msg'=>'TRUNCATE failed: '.mysqli_error($this->dblink)];
}
}
// Session-level speed knobs (local to this connection)
@mysqli_query($this->dblink, "SET innodb_flush_log_at_trx_commit=2");
@mysqli_query($this->dblink, "SET sync_binlog=0");
@mysqli_query($this->dblink, "SET unique_checks=0");
@mysqli_query($this->dblink, "SET foreign_key_checks=0");
// Read big windows; write in safe slices to avoid max_allowed_packet
if ($batch < 1000) $batch = 1000;
if ($batch > 100000) $batch = 100000;
if($countTotal < 1000) $sliceSize = 200;
elseif($countTotal < 5000) $sliceSize = 500;
elseif($countTotal > 5000) $sliceSize = 1000;
$total = 0;
$lastId = 0;
// Cursor pagination (no OFFSET)
while (true) {
$res = mysqli_query(
$this->dblink,
"SELECT id AS wref, x, y, fieldtype
FROM `$WDATA`
WHERE fieldtype IN (1,6) AND id > $lastId
ORDER BY id ASC
LIMIT $batch"
);
if (!$res) {
return ['ok'=>false,'msg'=>'SELECT failed: '.mysqli_error($this->dblink),'processed'=>$total,'target'=>$countTotal];
}
$rows = [];
while ($r = mysqli_fetch_assoc($res)) { $rows[] = $r; }
if (!$rows) break;
mysqli_begin_transaction($this->dblink);
$n = count($rows);
for ($i = 0; $i < $n; $i += $sliceSize) {
$chunk = array_slice($rows, $i, $sliceSize);
$values = [];
foreach ($chunk as $r) {
$x = (int)$r['x'];
$y = (int)$r['y'];
// Your existing helper:
$bonus = (int)$this->getBestOasisCropBonus($x, $y);
if ($bonus < 0) $bonus = 0;
if ($bonus > 150) $bonus = 150;
$values[] = sprintf("(%d,%d,%d,%d,%d)",
(int)$r['wref'], $x, $y, (int)$r['fieldtype'], $bonus
);
}
if ($values) {
// ODKU is cheaper than REPLACE (no DELETE)
$sql = "INSERT INTO `$CROP_TABLE`
(`wref`,`x`,`y`,`fieldtype`,`best_oasis_bonus`)
VALUES ".implode(',', $values)."
ON DUPLICATE KEY UPDATE
`x`=VALUES(`x`),
`y`=VALUES(`y`),
`fieldtype`=VALUES(`fieldtype`),
`best_oasis_bonus`=VALUES(`best_oasis_bonus`)";
if (!mysqli_query($this->dblink, $sql)) {
mysqli_rollback($this->dblink);
return ['ok'=>false,'msg'=>'INSERT failed: '.mysqli_error($this->dblink),'processed'=>$total,'target'=>$countTotal];
}
}
// progress after each slice
$total += count($chunk);
if ($reporter) {
$pct = $countTotal ? min(100, (int)floor(($total / $countTotal) * 100)) : 0;
$reporter($total, $countTotal, $pct);
}
}
mysqli_commit($this->dblink);
// advance cursor
$lastId = (int)$rows[$n - 1]['wref'];
}
// Restore checks (optional)
@mysqli_query($this->dblink, "SET unique_checks=1");
@mysqli_query($this->dblink, "SET foreign_key_checks=1");
// Analyze once at the end
@mysqli_query($this->dblink, "ANALYZE TABLE `$CROP_TABLE`");
if ($reporter) { $reporter($total, $countTotal, 100); }
return ['ok'=>true,'msg'=>'Croppers populated','processed'=>$total,'target'=>$countTotal];
}
// no need to cache, not used in any loops or more than once for each page load
public function getAvailableExpansionTraining() {
global $building, $session, $technology, $village;