DriveBackupV2

DriveBackupV2

46.6k Downloads

MySQL: OOM in backup thread due to storing dump in memory

oddstr13 opened this issue · 1 comments

commented

Describe the bug

The MySQL dump crashes due to attempting to store the whole dump in a StringBuilder in memory.

This fails when the database becomes large relative to the allocated minecraft memory, such as my coreprotect db which is rapidly approaching 1GB.

while(rs.next()) {
sql.append("(");
for(int i = 0; i < columnCount; i++) {
int columnType = metaData.getColumnType(i + 1);
int columnIndex = i + 1;
//this is the part where the values are processed based on their type
if(rs.getObject(columnIndex) == null) {
sql.append("").append(rs.getObject(columnIndex)).append(", ");
}
else if( columnType == Types.INTEGER || columnType == Types.TINYINT || columnType == Types.BIT) {
sql.append(rs.getInt(columnIndex)).append(", ");
}
else {
String val = rs.getString(columnIndex);
//escape the single quotes that might be in the value
val = val.replace("'", "\\'");
sql.append("'").append(val).append("', ");
}
}

To Reproduce

  1. Have more data in database than what fits in heap memory
  2. Run backup

Screenshots / Videos

mc         | [03:25:17 INFO]: Thread RCON Client /127.0.0.1 started
mc         | [03:25:17 INFO]: [DriveBackupV2] Forcing a backup
mc         | [03:25:17 INFO]: Thread RCON Client /127.0.0.1 shutting down
mc         | [03:25:20 INFO]: [DriveBackupV2] Creating backups, the server may lag for a little while...
mc         | [03:25:20 INFO]: Automatic saving is now disabled
mc         | [03:25:20 INFO]: [DriveBackupV2] Downloading databases from a MySQL server (<socket-addr>) to include in backup
mc         | [03:25:40 INFO]: Thread RCON Client /127.0.0.1 started
mc         | [03:25:40 INFO]: [Rcon: Saved the game]
mc         | [03:25:40 INFO]: Thread RCON Client /127.0.0.1 shutting down
mc         | [03:26:11 INFO]: [DriveBackupV2] Databases from a MySQL server (<socket-addr>) were successfully included in the backup
mc         | [03:26:12 INFO]: [DriveBackupV2] Doing backups for "./world_the_end"
mc         | [03:26:30 INFO]: [DriveBackupV2] Uploading file to Nextcloud
mc         | [03:27:09 INFO]: [DriveBackupV2] Creating backups, the server may lag for a little while...
mc         | [03:27:09 INFO]: Saving is already turned off
mc         | [03:27:09 INFO]: [DriveBackupV2] Downloading databases from a MySQL server (<socket-addr>) to include in backup
db         | 2022-01-10  3:27:14 3743 [Warning] Aborted connection 3743 to db: 'ban_manager' user: 'minecraft' host: '172.19.0.5' (Got an error reading communication packets)
db         | 2022-01-10  3:27:14 3744 [Warning] Aborted connection 3744 to db: 'discordsrv' user: 'minecraft' host: '172.19.0.5' (Got an error reading communication packets)
db         | 2022-01-10  3:27:14 3745 [Warning] Aborted connection 3745 to db: 'economyplus' user: 'minecraft' host: '172.19.0.5' (Got an error reading communication packets)
db         | 2022-01-10  3:27:20 3747 [Warning] Aborted connection 3747 to db: 'luckperms' user: 'minecraft' host: '172.19.0.5' (Got an error reading communication packets)
db         | 2022-01-10  3:27:44 3746 [Warning] Aborted connection 3746 to db: 'logblock' user: 'minecraft' host: '172.19.0.5' (Got an error reading communication packets)
mc         | [03:27:44 WARN]: [DriveBackupV2] Plugin DriveBackupV2 v1.5.4 generated an exception while executing task 11
mc         | java.lang.OutOfMemoryError: Java heap space
mc         | 	at java.util.Arrays.copyOf(Arrays.java:3537) ~[?:?]
mc         | 	at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:228) ~[?:?]
mc         | 	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:829) ~[?:?]
mc         | 	at java.lang.StringBuilder.append(StringBuilder.java:249) ~[?:?]
mc         | 	at ratismal.drivebackup.uploaders.mysql.MySQLUploader.getDataInsertStatement(MySQLUploader.java:209) ~[DriveBackupV2.jar:?]
mc         | 	at ratismal.drivebackup.uploaders.mysql.MySQLUploader.getInsertStatements(MySQLUploader.java:284) ~[DriveBackupV2.jar:?]
mc         | 	at ratismal.drivebackup.uploaders.mysql.MySQLUploader.downloadDatabase(MySQLUploader.java:86) ~[DriveBackupV2.jar:?]
mc         | 	at ratismal.drivebackup.UploadThread.makeExternalDatabaseBackup(UploadThread.java:513) ~[DriveBackupV2.jar:?]
mc         | 	at ratismal.drivebackup.UploadThread.run(UploadThread.java:232) ~[DriveBackupV2.jar:?]
mc         | 	at org.bukkit.craftbukkit.v1_18_R1.scheduler.CraftTask.run(CraftTask.java:101) ~[paper-1.18.1.jar:git-Paper-141]
mc         | 	at org.bukkit.craftbukkit.v1_18_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:57) ~[paper-1.18.1.jar:git-Paper-141]
mc         | 	at com.destroystokyo.paper.ServerSchedulerReportingWrapper.run(ServerSchedulerReportingWrapper.java:22) ~[paper-1.18.1.jar:git-Paper-141]
mc         | 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?]
mc         | 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?]
mc         | 	at java.lang.Thread.run(Thread.java:833) ~[?:?]
db         | 2022-01-10  3:27:50 3748 [Warning] Aborted connection 3748 to db: 'coreprotect' user: 'minecraft' host: '172.19.0.5' (Got an error reading communication packets)
mc         | [03:28:22 INFO]: [DriveBackupV2] File uploaded in 111.81 seconds (2040.72KB/s)
mc         | [03:28:22 INFO]: [DriveBackupV2] There are 13 file(s) which exceeds the local limit of 12, deleting oldest
mc         | [03:28:22 INFO]: [DriveBackupV2] Doing backups for "./world"

Server and Plugin Versions

Server: git-Paper-141 (MC: 1.18.1)
Plugin: https://github.com/oddstr13/DriveBackupV2/commits/odd-choices-2 (master + 1 commit)

Additional Context

(Also looks like db connections may not be getting properly closed)

commented

Fixed by #84 (at least as long as you're not storing huge blobs – each field is still read to memory before getting saved)