Skip to content
This repository was archived by the owner on May 27, 2020. It is now read-only.

Commit

Permalink
S3C-35 Refactoring of bucketfile (S3 file metadata backend)
Browse files Browse the repository at this point in the history
The changes allow bucketfile to use a new API in Arsenal to
communicate with a remote leveldb database, containing sublevels for
bucket storage. Metadata is still stored on a local levelDB server,
but it should now be easy to move the storage logic in a new daemon
running on a remote server, and it should be robust.

Instead of relying on the existing implementation of multilevel, it
uses client/server wrappers around a new level-net communication
protocol and API in Arsenal based on socket.io to exchange messages.

It shall be compatible with the existing metadata since it still uses
the core sublevel module for the storage logic, only the RPC procotol
has changed.

Test done:

 - put a few 100s of files in different S3 subdirectories
 - list directories and subdirectories
 - get/delete files
 - multi-part upload
 - introduce random connection errors (tcpkill) to check robustness
   and automatic reconnection
  • Loading branch information
jonathan-gramain committed Apr 6, 2017
1 parent d1efb3b commit b9adc5e
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 349 deletions.
4 changes: 4 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,9 @@
},
"healthChecks": {
"allowFrom": ["127.0.0.1/8", "::1"]
},
"metadataDaemon": {
"host": "localhost",
"port": 9990
}
}
60 changes: 3 additions & 57 deletions init.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,61 +6,11 @@ const fs = require('fs');
const os = require('os');

const async = require('async');
const uuid = require('node-uuid');

const constants = require('./constants').default;
const config = require('./lib/Config.js').default;
const logger = require('./lib/utilities/logger.js').logger;

let ioctl;
try {
ioctl = require('ioctl');
} catch (err) {
logger.warn('ioctl dependency is unavailable. skipping...');
}

function _setDirSyncFlag(path) {
const GETFLAGS = 2148034049;
const SETFLAGS = 1074292226;
const FS_DIRSYNC_FL = 65536;
const buffer = Buffer.alloc(8, 0);
const pathFD = fs.openSync(path, 'r');
const status = ioctl(pathFD, GETFLAGS, buffer);
assert.strictEqual(status, 0);
const currentFlags = buffer.readUIntLE(0, 8);
const flags = currentFlags | FS_DIRSYNC_FL;
buffer.writeUIntLE(flags, 0, 8);
const status2 = ioctl(pathFD, SETFLAGS, buffer);
assert.strictEqual(status2, 0);
fs.closeSync(pathFD);
const pathFD2 = fs.openSync(path, 'r');
const confirmBuffer = Buffer.alloc(8, 0);
ioctl(pathFD2, GETFLAGS, confirmBuffer);
assert.strictEqual(confirmBuffer.readUIntLE(0, 8),
currentFlags | FS_DIRSYNC_FL, 'FS_DIRSYNC_FL not set');
logger.info('FS_DIRSYNC_FL set');
fs.closeSync(pathFD2);
}

function printUUID(metadataPath) {
const uuidFile = `${metadataPath}/uuid`;

try {
fs.accessSync(uuidFile, fs.F_OK | fs.R_OK);
} catch (e) {
if (e.code === 'ENOENT') {
const v = uuid.v4();
const fd = fs.openSync(uuidFile, 'w');
fs.writeSync(fd, v.toString());
fs.closeSync(fd);
} else {
throw e;
}
}

const uuidValue = fs.readFileSync(uuidFile);
logger.info(`This deployment's identifier is ${uuidValue}`);
}
const storageUtils = require('arsenal').storage.utils;

// If neither data nor metadata is using the file backend,
// there is no need to init
Expand All @@ -71,18 +21,15 @@ if (config.backends.data !== 'file' && config.backends.data !== 'multiple' &&
}

const dataPath = config.filePaths.dataPath;
const metadataPath = config.filePaths.metadataPath;

fs.accessSync(dataPath, fs.F_OK | fs.R_OK | fs.W_OK);
fs.accessSync(metadataPath, fs.F_OK | fs.R_OK | fs.W_OK);
const warning = 'WARNING: Synchronization directory updates are not ' +
'supported on this platform. Newly written data could be lost ' +
'if your system crashes before the operating system is able to ' +
'write directory updates.';
if (os.type() === 'Linux' && os.endianness() === 'LE' && ioctl) {
if (os.type() === 'Linux' && os.endianness() === 'LE') {
try {
_setDirSyncFlag(dataPath);
_setDirSyncFlag(metadataPath);
storageUtils.setDirSyncFlag(dataPath);
} catch (err) {
logger.warn(warning, { error: err.stack });
}
Expand All @@ -105,5 +52,4 @@ async.eachSeries(subDirs, (subDirName, next) => {
err => {
assert.strictEqual(err, null, `Error creating data files ${err}`);
logger.info('Init complete. Go forth and store data.');
printUUID(metadataPath);
});
14 changes: 14 additions & 0 deletions lib/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,20 @@ class Config {
}
}

if (config.metadataDaemon) {
this.metadataDaemon = {};
assert.strictEqual(
typeof config.metadataDaemon.host, 'string',
'bad config: metadata daemon host must be a string');
this.metadataDaemon.host = config.metadataDaemon.host;

assert(Number.isInteger(config.metadataDaemon.port)
&& config.metadataDaemon.port > 0,
'bad config: metadata daemon port must be a ' +
'positive integer');
this.metadataDaemon.port = config.metadataDaemon.port;
}

if (process.env.ENABLE_LOCAL_CACHE) {
this.localCache = defaultLocalCache;
}
Expand Down
Loading

0 comments on commit b9adc5e

Please sign in to comment.