Loading Design.md 0 → 100644 +42 −0 Original line number Diff line number Diff line # Kinetic library Kinetic library create and handle requests to communicate with kinetic drives. It is based on the kinetic protocol, available at https://github.com/Kinetic/kinetic-protocol ## Implementation ### Architecture The kinetic library consist of a principal class PDU that handles the requests. It takes the buffer received from the kinetic drives or the client and decode it. The request are in protobuf (https://developers.google.com/protocol-buffers/) so they are small. The library don't do the I/O with the kinetic drives. The I/O have to be done by the user. The library encode and decode protobuf messages following the kinetic protocol. In this library we got requests that extend from PDU. That design allow to create requests easily. A request will just be an instance of PDU. ### Library specifications Right now, the following operations are implemented: - PDU, - InitPDU (server), - GetLogPDU (client), - GetLogResponsePDU, - FlushPDU (client), - FlushResponsePDU (server), - SetClusterVersionPDU (client), - SetupResponsePDU (server), - NoOpPDU (client), - NoOpResponsePDU (server), - PutPDU (client), - PutResponsePDU (server), - GetPDU (client), - GetResponsePDU (server), - DeletePDU (client), - DeleteResponsePDU (server), README.md +123 −2 Original line number Diff line number Diff line # kinetic-js Kinetic Java Script Library # kineticlib -- JavaScript Kinetic library Node.js library for using the [Kinetic open storage protocol](https://github.com/Kinetic/kinetic-protocol). This library supports protocol 3.0.7 ## Requirements This project's code is written in ES6. If you need to include it from older JavaScript versions, use babel or an equivalent. Install npm dependencies using `npm install`. ## Examples Create a PDU for a PUT at key "mykey" and send it to localhost on port 1234: ```js import net from 'net'; import kinetic from 'kineticlib'; const chunk = new Buffer("D4T4d4t4D4T4d4t4D4T4d4t4D4T4d4t4D4T4d4t4"); const options = { dbVersion: new Buffer('44'), // The actual version of the value in // the database newVersion: new Buffer('45'), // The updated version of the value in // the database force: false // Setting force to true ignores // potential version mismatches and // carries out the operation. clusterVersion // the cluster version } const pdu = new kinetic.PutPDU( 1, // sequence number "mykey", // key chunk.length, // chunkSize options, // options ); const sock = net.connect(1234, 'localhost'); sock.on("end", () => { process.stdout.write("PDU sent through the network.\n"); }); sock.write(pdu.read()); sock.write(chunk); ``` Decode a PDU message from a buffer: ```js const rawData = new Buffer('\x46\x00\x00\x00\x32\x00' ... ); const pdu = new kinetic.PDU(rawData); const type = pdu.getMessageType(); process.stdout.write("Received " + kinetic.getOpName(type) + " PDU.\n"); if (type === kinetic.ops.GET) process.stdout.write("Peer is trying to GET key " + pdu.getKey() + ".\n"); ``` Asynchronously decode a PDU from a stream (e.g. a socket): Handle a decoding error: ```js const badBuffer = new Buffer('\x46\x00\x00\x00\x32\x00'); try { const pdu = new kinetic.PDU(badBuffer); } catch (e) { if (e.badLength) process.stdout.write("Message is either truncated or too long.\n"); else if (e.hmacFail) process.stdout.write("Message is corrupted.\n"); // ... } ``` Receive a response from kinetic: ```js const header = socket.sock.read(HEADER_SZ); const protobufSize = header.readInt32BE(1); const rawData = socket.sock.read(protobufSize); const pdu = new kinetic.PDU(Buffer.concat([header, rawData])); const statusCode = pdu.getStatusCode(); const connectionInfos = {}; let chunkSize = 0; let chunk = Buffer.from(0); switch (pdu.getMessageType()) { //Initial pdu received from the kinetic drive with infos case null: //These infos are needed for the nexts request connectionInfos.connectionID = pdu.getConnectionId(); connectionInfos.clusterVersion = pdu.getClusterVersion(); break; case kinetic.ops.PUT_RESPONSE: if (statusCode !== kinetic.errors.SUCCESS) { return callback(pdu.getErrorMessage()); } return callback(null, pdu); break; case kinetic.ops.DELETE_RESPONSE: if (statusCode !== kinetic.errors.SUCCESS) { return callback(pdu.getErrorMessage()); } return callback(null, pdu); break; case kinetic.ops.GET_RESPONSE: if (statusCode !== kinetic.errors.SUCCESS) { return callback(pdu.getErrorMessage()); } chunkSize = pdu.getChunkSize(); chunk = socket.sock.read(chunkSize); return callback(null, pdu, chunk); break; default: break; ``` TESTING.md 0 → 100644 +124 −0 Original line number Diff line number Diff line # Testing kineticlib This repo is full of tests to ensure our software is working now, and will keep working as we add more code. * [Unit tests](#unit-tests) to test individual functions and make sure they behave correctly with specific sets of arguments. * [Functional tests](#functional-tests) to test the compatibility between our kinetic library with the kinetic device simulator. #### I wrote a patch and I want to check tests are passing! Sure. You can run some tests locally: ``` npm run --silent lint npm run --silent test ``` Integration and performance tests really need a CI infrastructure to simulate multiple machines and work properly. ## Unit tests Unit tests are located in the `tests/unit` directory. ### Architecture * PDU generation * mocha ### Method * Generate some PDU and write it in a file with a simple script : ```node import fs from 'fs'; import kinetic from '../index.js'; let rawData = undefined; const k = new kinetic.NoOpPDU(123); // if you want a put or a get response, you need a chunk : // k.setChunk(new Buffer("HI EVERYBODY")); const pduHeader = new Buffer(9); pduHeader.writeInt8(kinetic.getVersion(), 0); pduHeader.writeInt32BE(k.getProtobufSize(), 1); pduHeader.writeInt32BE(k.getChunkSize(), 5); const wstream = fs.createWriteStream('NOOP_request', 'ascii'); if (k.getChunk() !== undefined) rawData = Buffer.concat( [pduHeader, k._message.toBuffer(), k.getChunk()]); else rawData = Buffer.concat([pduHeader, k._message.toBuffer()]); wstream.write(rawData); wstream.end(rawData); ``` * It is possible to check the message : ```node const pdu = new Kinetic.PDU(rawData); logger.info(util.inspect(pdu._message,{showHidden: false, depth: null})); ``` * Now let's convert it to hex : ```node import fs from 'fs'; const requestsArr = [ 'NOOP_request', ]; function writeHex(request) { const file = fs.readFileSync(request , 'hex'); let result = ''; for (let i = 0; i < file.length; i += 2) { result += '\\x${file[i]}${file[i + 1]}'; } fs.writeFileSync(request + '_Hexatify', result); } requestsArr.forEach(writeHex); ``` - You can also use : ``` hexdump -C FILE | cut -b10-33,35-58 | sed 's/\s\+$//g;s/ /\\x/g' ``` ### Functions tested * Kinetic - Kinetic.PDU constructor() - For all request check if the parsing works - Check the fields in the PDU - The responses PDU are generated from the simulator - Kinetic.PDU send() - NOOP - PUT - GET - DELETE - FLUSH - GETLOG - Variables type (Buffer for db version and key) - PUT - GET - DELETE No newline at end of file Loading
Design.md 0 → 100644 +42 −0 Original line number Diff line number Diff line # Kinetic library Kinetic library create and handle requests to communicate with kinetic drives. It is based on the kinetic protocol, available at https://github.com/Kinetic/kinetic-protocol ## Implementation ### Architecture The kinetic library consist of a principal class PDU that handles the requests. It takes the buffer received from the kinetic drives or the client and decode it. The request are in protobuf (https://developers.google.com/protocol-buffers/) so they are small. The library don't do the I/O with the kinetic drives. The I/O have to be done by the user. The library encode and decode protobuf messages following the kinetic protocol. In this library we got requests that extend from PDU. That design allow to create requests easily. A request will just be an instance of PDU. ### Library specifications Right now, the following operations are implemented: - PDU, - InitPDU (server), - GetLogPDU (client), - GetLogResponsePDU, - FlushPDU (client), - FlushResponsePDU (server), - SetClusterVersionPDU (client), - SetupResponsePDU (server), - NoOpPDU (client), - NoOpResponsePDU (server), - PutPDU (client), - PutResponsePDU (server), - GetPDU (client), - GetResponsePDU (server), - DeletePDU (client), - DeleteResponsePDU (server),
README.md +123 −2 Original line number Diff line number Diff line # kinetic-js Kinetic Java Script Library # kineticlib -- JavaScript Kinetic library Node.js library for using the [Kinetic open storage protocol](https://github.com/Kinetic/kinetic-protocol). This library supports protocol 3.0.7 ## Requirements This project's code is written in ES6. If you need to include it from older JavaScript versions, use babel or an equivalent. Install npm dependencies using `npm install`. ## Examples Create a PDU for a PUT at key "mykey" and send it to localhost on port 1234: ```js import net from 'net'; import kinetic from 'kineticlib'; const chunk = new Buffer("D4T4d4t4D4T4d4t4D4T4d4t4D4T4d4t4D4T4d4t4"); const options = { dbVersion: new Buffer('44'), // The actual version of the value in // the database newVersion: new Buffer('45'), // The updated version of the value in // the database force: false // Setting force to true ignores // potential version mismatches and // carries out the operation. clusterVersion // the cluster version } const pdu = new kinetic.PutPDU( 1, // sequence number "mykey", // key chunk.length, // chunkSize options, // options ); const sock = net.connect(1234, 'localhost'); sock.on("end", () => { process.stdout.write("PDU sent through the network.\n"); }); sock.write(pdu.read()); sock.write(chunk); ``` Decode a PDU message from a buffer: ```js const rawData = new Buffer('\x46\x00\x00\x00\x32\x00' ... ); const pdu = new kinetic.PDU(rawData); const type = pdu.getMessageType(); process.stdout.write("Received " + kinetic.getOpName(type) + " PDU.\n"); if (type === kinetic.ops.GET) process.stdout.write("Peer is trying to GET key " + pdu.getKey() + ".\n"); ``` Asynchronously decode a PDU from a stream (e.g. a socket): Handle a decoding error: ```js const badBuffer = new Buffer('\x46\x00\x00\x00\x32\x00'); try { const pdu = new kinetic.PDU(badBuffer); } catch (e) { if (e.badLength) process.stdout.write("Message is either truncated or too long.\n"); else if (e.hmacFail) process.stdout.write("Message is corrupted.\n"); // ... } ``` Receive a response from kinetic: ```js const header = socket.sock.read(HEADER_SZ); const protobufSize = header.readInt32BE(1); const rawData = socket.sock.read(protobufSize); const pdu = new kinetic.PDU(Buffer.concat([header, rawData])); const statusCode = pdu.getStatusCode(); const connectionInfos = {}; let chunkSize = 0; let chunk = Buffer.from(0); switch (pdu.getMessageType()) { //Initial pdu received from the kinetic drive with infos case null: //These infos are needed for the nexts request connectionInfos.connectionID = pdu.getConnectionId(); connectionInfos.clusterVersion = pdu.getClusterVersion(); break; case kinetic.ops.PUT_RESPONSE: if (statusCode !== kinetic.errors.SUCCESS) { return callback(pdu.getErrorMessage()); } return callback(null, pdu); break; case kinetic.ops.DELETE_RESPONSE: if (statusCode !== kinetic.errors.SUCCESS) { return callback(pdu.getErrorMessage()); } return callback(null, pdu); break; case kinetic.ops.GET_RESPONSE: if (statusCode !== kinetic.errors.SUCCESS) { return callback(pdu.getErrorMessage()); } chunkSize = pdu.getChunkSize(); chunk = socket.sock.read(chunkSize); return callback(null, pdu, chunk); break; default: break; ```
TESTING.md 0 → 100644 +124 −0 Original line number Diff line number Diff line # Testing kineticlib This repo is full of tests to ensure our software is working now, and will keep working as we add more code. * [Unit tests](#unit-tests) to test individual functions and make sure they behave correctly with specific sets of arguments. * [Functional tests](#functional-tests) to test the compatibility between our kinetic library with the kinetic device simulator. #### I wrote a patch and I want to check tests are passing! Sure. You can run some tests locally: ``` npm run --silent lint npm run --silent test ``` Integration and performance tests really need a CI infrastructure to simulate multiple machines and work properly. ## Unit tests Unit tests are located in the `tests/unit` directory. ### Architecture * PDU generation * mocha ### Method * Generate some PDU and write it in a file with a simple script : ```node import fs from 'fs'; import kinetic from '../index.js'; let rawData = undefined; const k = new kinetic.NoOpPDU(123); // if you want a put or a get response, you need a chunk : // k.setChunk(new Buffer("HI EVERYBODY")); const pduHeader = new Buffer(9); pduHeader.writeInt8(kinetic.getVersion(), 0); pduHeader.writeInt32BE(k.getProtobufSize(), 1); pduHeader.writeInt32BE(k.getChunkSize(), 5); const wstream = fs.createWriteStream('NOOP_request', 'ascii'); if (k.getChunk() !== undefined) rawData = Buffer.concat( [pduHeader, k._message.toBuffer(), k.getChunk()]); else rawData = Buffer.concat([pduHeader, k._message.toBuffer()]); wstream.write(rawData); wstream.end(rawData); ``` * It is possible to check the message : ```node const pdu = new Kinetic.PDU(rawData); logger.info(util.inspect(pdu._message,{showHidden: false, depth: null})); ``` * Now let's convert it to hex : ```node import fs from 'fs'; const requestsArr = [ 'NOOP_request', ]; function writeHex(request) { const file = fs.readFileSync(request , 'hex'); let result = ''; for (let i = 0; i < file.length; i += 2) { result += '\\x${file[i]}${file[i + 1]}'; } fs.writeFileSync(request + '_Hexatify', result); } requestsArr.forEach(writeHex); ``` - You can also use : ``` hexdump -C FILE | cut -b10-33,35-58 | sed 's/\s\+$//g;s/ /\\x/g' ``` ### Functions tested * Kinetic - Kinetic.PDU constructor() - For all request check if the parsing works - Check the fields in the PDU - The responses PDU are generated from the simulator - Kinetic.PDU send() - NOOP - PUT - GET - DELETE - FLUSH - GETLOG - Variables type (Buffer for db version and key) - PUT - GET - DELETE No newline at end of file