optimize backup tile creation
This commit is contained in:
parent
5db3083044
commit
b436937f86
|
@ -109,12 +109,13 @@ class Palette {
|
|||
buffer2ABGR(chunkBuffer) {
|
||||
const { length } = chunkBuffer;
|
||||
const colors = new Uint32Array(length);
|
||||
const { abgr } = this;
|
||||
let value;
|
||||
|
||||
let pos = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
value = (chunkBuffer[i] & 0x3F);
|
||||
colors[pos++] = this.abgr[value];
|
||||
colors[pos++] = abgr[value];
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
@ -129,16 +130,16 @@ class Palette {
|
|||
const colors = new Uint8Array(length * 3);
|
||||
let color;
|
||||
let value;
|
||||
const buffer = chunkBuffer;
|
||||
const { rgb } = this;
|
||||
|
||||
let c = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
value = buffer[i];
|
||||
value = chunkBuffer[i];
|
||||
|
||||
color = (value & 0x3F) * 3;
|
||||
colors[c++] = this.rgb[color++];
|
||||
colors[c++] = this.rgb[color++];
|
||||
colors[c++] = this.rgb[color];
|
||||
colors[c++] = rgb[color++];
|
||||
colors[c++] = rgb[color++];
|
||||
colors[c++] = rgb[color];
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
|
|
@ -13,22 +13,6 @@ import Palette from './Palette';
|
|||
import { TILE_SIZE } from './constants';
|
||||
|
||||
|
||||
/*
|
||||
* take chunk buffer and pad it to a specific length
|
||||
* Fill missing pixels with zeros
|
||||
* @param length target length
|
||||
*/
|
||||
function padChunk(chunk, length) {
|
||||
let retChunk = chunk;
|
||||
if (!chunk || !chunk.length) {
|
||||
retChunk = Buffer.alloc(length);
|
||||
} else if (chunk.length < length) {
|
||||
const padding = Buffer.alloc(length - chunk.length);
|
||||
retChunk = Buffer.concat([chunk, padding]);
|
||||
}
|
||||
return retChunk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy canvases from one redis instance to another
|
||||
* @param canvasRedis redis from where to get the data
|
||||
|
@ -98,8 +82,8 @@ export async function incrementialBackupRedis(
|
|||
backupDir,
|
||||
) {
|
||||
const ids = Object.keys(canvases);
|
||||
for (let i = 0; i < ids.length; i += 1) {
|
||||
const id = ids[i];
|
||||
for (let ind = 0; ind < ids.length; ind += 1) {
|
||||
const id = ids[ind];
|
||||
|
||||
const canvas = canvases[id];
|
||||
if (canvas.v || canvas.hid) {
|
||||
|
@ -162,44 +146,49 @@ export async function incrementialBackupRedis(
|
|||
);
|
||||
}
|
||||
|
||||
// is gonna be an Uint32Array
|
||||
let tileBuffer = null;
|
||||
|
||||
try {
|
||||
if (!oldChunk && !curChunk) {
|
||||
continue;
|
||||
}
|
||||
if (oldChunk && !curChunk) {
|
||||
// one does not exist
|
||||
curChunk = Buffer.alloc(TILE_SIZE * TILE_SIZE);
|
||||
tileBuffer = palette.buffer2ABGR(curChunk);
|
||||
} else if (!oldChunk && curChunk) {
|
||||
tileBuffer = new Uint32Array(TILE_SIZE * TILE_SIZE);
|
||||
const pxl = 0;
|
||||
while (pxl < curChunk.length) {
|
||||
const clrIndex = curChunk[pxl] & 0x3F;
|
||||
if (clrIndex > 0) {
|
||||
const color = palette.abgr[clrIndex];
|
||||
tileBuffer[pxl] = color;
|
||||
if (!oldChunk) {
|
||||
oldChunk = Buffer.allocUnsafe(0);
|
||||
}
|
||||
if (!curChunk) {
|
||||
curChunk = Buffer.allocUnsafe(0);
|
||||
}
|
||||
|
||||
const { abgr } = palette;
|
||||
const compLength = Math.min(oldChunk.length, curChunk.length);
|
||||
tileBuffer = Buffer.allocUnsafe(TILE_SIZE ** 2 * 4);
|
||||
for (let i = 0; i < compLength; i += 1) {
|
||||
const curPxl = curChunk[i];
|
||||
if (oldChunk[i] !== curPxl) {
|
||||
tileBuffer.writeUInt32BE(i * 4, abgr[curPxl & 0x3F]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (curChunk.length < oldChunk.length) {
|
||||
curChunk = padChunk(curChunk, oldChunk.length);
|
||||
} else if (curChunk.length > oldChunk.length) {
|
||||
oldChunk = padChunk(oldChunk, curChunk.length);
|
||||
|
||||
const oldChunkLength = oldChunk.length;
|
||||
const curChunkLength = curChunk.length;
|
||||
|
||||
for (let i = oldChunkLength; i < curChunkLength; i += 1) {
|
||||
tileBuffer.writeUInt32BE(i * 4, abgr[curChunk[i] & 0x3F]);
|
||||
}
|
||||
// both exist and are the same length
|
||||
tileBuffer = new Uint32Array(TILE_SIZE * TILE_SIZE);
|
||||
let pxl = 0;
|
||||
while (pxl < curChunk.length) {
|
||||
if (curChunk[pxl] !== oldChunk[pxl]) {
|
||||
const color = palette.abgr[curChunk[pxl] & 0x3F];
|
||||
tileBuffer[pxl] = color;
|
||||
|
||||
if (oldChunkLength > curChunkLength) {
|
||||
const blank = abgr[0];
|
||||
for (let i = curChunkLength; i < oldChunkLength; i += 1) {
|
||||
if (oldChunk[i] !== 0) {
|
||||
tileBuffer.writeUInt32BE(i * 4, blank);
|
||||
}
|
||||
pxl += 1;
|
||||
}
|
||||
}
|
||||
|
||||
const curLength = Math.max(oldChunkLength, curChunkLength) * 4;
|
||||
if (curLength < tileBuffer.length) {
|
||||
tileBuffer.fill(0, curLength);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
// eslint-disable-next-line max-len
|
||||
|
@ -208,7 +197,6 @@ export async function incrementialBackupRedis(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (tileBuffer) {
|
||||
try {
|
||||
if (!createdDir && !fs.existsSync(xBackupDir)) {
|
||||
createdDir = true;
|
||||
|
@ -217,7 +205,7 @@ export async function incrementialBackupRedis(
|
|||
const filename = `${xBackupDir}/${y}.png`;
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await sharp(
|
||||
Buffer.from(tileBuffer.buffer), {
|
||||
tileBuffer, {
|
||||
raw: {
|
||||
width: TILE_SIZE,
|
||||
height: TILE_SIZE,
|
||||
|
@ -235,7 +223,6 @@ export async function incrementialBackupRedis(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const time = Date.now() - startTime;
|
||||
console.log(
|
||||
`Finished Incremential backup of ${amount} chunks in ${time}ms.`,
|
||||
|
@ -256,8 +243,8 @@ export async function createPngBackup(
|
|||
backupDir,
|
||||
) {
|
||||
const ids = Object.keys(canvases);
|
||||
for (let i = 0; i < ids.length; i += 1) {
|
||||
const id = ids[i];
|
||||
for (let ind = 0; ind < ids.length; ind += 1) {
|
||||
const id = ids[ind];
|
||||
|
||||
const canvasBackupDir = `${backupDir}/${id}`;
|
||||
if (!fs.existsSync(canvasBackupDir)) {
|
||||
|
@ -296,13 +283,27 @@ export async function createPngBackup(
|
|||
);
|
||||
}
|
||||
if (chunk && chunk.length) {
|
||||
chunk = padChunk(chunk, TILE_SIZE * TILE_SIZE);
|
||||
const textureBuffer = palette.buffer2RGB(chunk);
|
||||
const filename = `${xBackupDir}/${y}.png`;
|
||||
try {
|
||||
const tileBuffer = Buffer.allocUnsafe(TILE_SIZE ** 2 * 4);
|
||||
const chunkLength = chunk.length;
|
||||
const { abgr } = palette;
|
||||
for (let i = 0; i < chunkLength; i += 1) {
|
||||
tileBuffer.writeUInt32BE(
|
||||
i * 4,
|
||||
abgr[chunk[i] & 0x3F],
|
||||
);
|
||||
}
|
||||
|
||||
const curLength = chunkLength * 4;
|
||||
if (curLength < tileBuffer.length) {
|
||||
tileBuffer.fill(0, curLength);
|
||||
}
|
||||
|
||||
const filename = `${xBackupDir}/${y}.png`;
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await sharp(
|
||||
Buffer.from(textureBuffer.buffer), {
|
||||
tileBuffer, {
|
||||
raw: {
|
||||
width: TILE_SIZE,
|
||||
height: TILE_SIZE,
|
||||
|
|
|
@ -43,6 +43,10 @@ class RedisCanvas {
|
|||
key,
|
||||
);
|
||||
if (padding > 0 && chunk && chunk.length < padding) {
|
||||
/*
|
||||
* this padding is slow and should be avoided,
|
||||
* better deal with non-full-size chunks yourself
|
||||
*/
|
||||
const pad = Buffer.alloc(padding - chunk.length);
|
||||
chunk = Buffer.concat([chunk, pad]);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user