Skip to content

Commit

Permalink
remove batched release, replace hash with cyrb53
Browse files Browse the repository at this point in the history
  • Loading branch information
howardchung committed Dec 26, 2024
1 parent 0189b06 commit 1ae3e0a
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 28 deletions.
18 changes: 8 additions & 10 deletions server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import { deleteUser, validateUserToken } from './utils/firebase';
import path from 'path';
import { getStartOfDay } from './utils/time';
import { getBgVMManagers, getSessionLimitSeconds } from './vm/utils';
import { hashString } from './utils/string';
import { postgres, insertObject, upsertObject } from './utils/postgres';
import axios from 'axios';
import crypto from 'crypto';
Expand All @@ -51,7 +50,6 @@ if (process.env.NODE_ENV === 'development') {
const gzip = util.promisify(zlib.gzip);

const releaseInterval = 5 * 60 * 1000;
const releaseBatches = config.NODE_ENV === 'development' ? 1 : 10;
const app = express();
let server: any = null;
if (config.SSL_KEY_FILE && config.SSL_CRT_FILE) {
Expand Down Expand Up @@ -89,7 +87,7 @@ async function init() {
server.listen(config.PORT, config.HOST);
// Following functions iterate over in-memory rooms
setInterval(minuteMetrics, 60 * 1000);
setInterval(release, releaseInterval / releaseBatches);
setInterval(release, releaseInterval);
setInterval(freeUnusedRooms, 5 * 60 * 1000);
saveRooms();
if (process.env.NODE_ENV === 'development') {
Expand Down Expand Up @@ -607,15 +605,12 @@ async function saveRooms() {
}
}

let currBatch = 0;
async function release() {
// Reset VMs in rooms that are:
// older than the session limit
// assigned to a room with no users
const roomArr = Array.from(rooms.values()).filter((room) => {
return hashString(room.roomId) % releaseBatches === currBatch;
});
console.log('[RELEASE][%s] %s rooms in batch', currBatch, roomArr.length);
const roomArr = Array.from(rooms.values());
console.log('[RELEASE] %s rooms in batch', roomArr.length);
for (let i = 0; i < roomArr.length; i++) {
const room = roomArr[i];
if (room.vBrowser && room.vBrowser.assignTime) {
Expand All @@ -628,7 +623,7 @@ async function release() {
const isRoomIdle =
Date.now() - Number(room.lastUpdateTime) > 5 * 60 * 1000;
if (isTimedOut || (isRoomEmpty && isRoomIdle)) {
console.log('[RELEASE][%s] VM in room:', currBatch, room.roomId);
console.log('[RELEASE] VM in room:', room.roomId);
room.stopVBrowserInternal();
if (isTimedOut) {
room.addChatMessage(null, {
Expand All @@ -650,8 +645,11 @@ async function release() {
});
}
}
// We want to spread out the jobs over about half the release interval
// This gives other jobs some CPU time
const waitTime = releaseInterval / 2 / roomArr.length;
await new Promise((resolve) => setTimeout(resolve, waitTime));
}
currBatch = (currBatch + 1) % releaseBatches;
}

async function minuteMetrics() {
Expand Down
8 changes: 0 additions & 8 deletions server/utils/string.ts

This file was deleted.

40 changes: 40 additions & 0 deletions src/utils/hash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Extremely simple function to convert a string to a number for bucketing
// Will return the same value for the same letters, regardless of order (collisions very likely)
export function hashString(input: string) {
var hash = 0;
for (var i = 0; i < input.length; i++) {
var charCode = input.charCodeAt(i);
hash += charCode;
}
return hash;
}

// An improved alternative:
// cyrb53 (c) 2018 bryc (github.com/bryc). License: Public domain. Attribution appreciated.
// A fast and simple 64-bit (or 53-bit) string hash function with decent collision resistance.
// Largely inspired by MurmurHash2/3, but with a focus on speed/simplicity.
// See https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript/52171480#52171480
// https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js
export const cyrb53 = (str: string, seed = 0) => {
let h1 = 0xdeadbeef ^ seed,
h2 = 0x41c6ce57 ^ seed;
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i);
h1 = Math.imul(h1 ^ ch, 2654435761);
h2 = Math.imul(h2 ^ ch, 1597334677);
}
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);

return 4294967296 * (2097151 & h2) + (h1 >>> 0);
};
// If we want all 64 bits of the output:
/*
return [h2>>>0, h1>>>0];
// or
return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
// or
return 4294967296n * BigInt(h2) + BigInt(h1);
*/
12 changes: 2 additions & 10 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { MD5 } from './md5';
import firebase from 'firebase/compat/app';
import { XMLParser } from 'fast-xml-parser';
import config from '../config';
import { cyrb53 } from './hash';

export function formatTimestamp(input: any, wallClock?: boolean): string {
if (
Expand Down Expand Up @@ -54,15 +55,6 @@ export function formatSize(input: number) {
return input + ' B';
}

export function hashString(input: string) {
var hash = 0;
for (var i = 0; i < input.length; i++) {
var charCode = input.charCodeAt(i);
hash += charCode;
}
return hash;
}

export const colorMappings: StringDict = {
red: 'B03060',
orange: 'FE9A76',
Expand Down Expand Up @@ -98,7 +90,7 @@ export function getColorForString(id: string) {
if (colorCache[id]) {
return colors[colorCache[id]];
}
colorCache[id] = Math.abs(hashString(id)) % colors.length;
colorCache[id] = Math.abs(cyrb53(id)) % colors.length;
return colors[colorCache[id]];
}

Expand Down

0 comments on commit 1ae3e0a

Please sign in to comment.