Commit be75c491 authored by Antonin Coulibaly's avatar Antonin Coulibaly
Browse files

Add documentation

parent 5d89c44b
Loading
Loading
Loading
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),
+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