Failed to retrieve machine-readable status via the FoundationDB Java Client API

bindings

(Jun Li) #1

To retrieve the machine-readable status, the following Python code works on my FDB cluster:

import fdb
import json

fab.api_version(600)
db=fdb.open()
status = json.loads(db[’\xff\xff/status/json’])
print status

Then I have the following Java code to try to retrieve the same status:

public class FoundationDBClusterStatus {

private static final FDB fdb;
private static final Database db;

static {
    fdb = FDB.selectAPIVersion(600);
    db = fdb.open("/<path>/fdb.cluster");
}

public static void main(String[] args) throws InterruptedException {
    String statusInJson = db.run(tr -> {
        TransactionOptions options = tr.options();
        options.setReadSystemKeys();
        byte[] result = tr.get(Tuple.from((byte)0xff, (byte)0xff, "/status/json".getBytes()).pack()).join();
        if (result != null) {
            System.out.println("result is not null");
            return Tuple.fromBytes(result).getString(0);
        }
        else{
            System.out.println("result is null");
            return "";
        }
    });

    System.out.println("status in json is: " + statusInJson);
}

}

I am able to get the database object, but always get the null byte result, even though I tried to set that the key access is a system key access. Do I miss something on encoding the key?

Thanks.


(gaurav) #2

You might have to form the key directly as a byte, without involving Tuple layer. Tuple layer encoding would create a byte array that is different from \xff\xff/status/json


(Jun Li) #3

Thank you for the suggestion. After I changed the code to manually construct the byte for \xff\xff/status/json, I was able to retrieve correctly the status information. The returned byte result also should not pass through the Tuple layer for String unmarshalling. The following is the code that works:

public static byte[] stringToBytesASCII(String str) {
    char[] buffer = str.toCharArray();
    byte[] b = new byte[buffer.length];
    for (int i = 0; i < b.length; i++) {
        b[i] = (byte) buffer[i];
    }
    return b;
}

public static void main(String[] args) throws InterruptedException {
    // we have to build the byte array and not using the Tuple layer APIs.
    String statusInJson = db.run(tr -> {
        TransactionOptions options = tr.options();
        options.setReadSystemKeys();
        byte[] stringPartOfKey= stringToBytesASCII("/status/json");
        byte[] fullKey  =new byte[stringPartOfKey.length +2];

        fullKey[0] = (byte)0xff;
        fullKey[1] = (byte)0xff;

        for (int i=2; i<fullKey.length; i++) {
            fullKey[i] = stringPartOfKey[i-2];
        }

        //same to the output of the key value that we should not rely on the Tuple layer APIs.
        byte[] result = tr.get(fullKey).join();

        try {
            String str = new String(result, "UTF-8");
            return str;
        }
        catch (Exception ex) {
            System.out.println("encounter exception: " + ex.getMessage());
            return "";
        }

    });

    System.out.println("status in json is: " + statusInJson);
}

(Esteban S.) #4

Perhaps a simplified version of the above using ByteBuffers instead:

    public String getStatus() {
    return db.run(tr -> {
        TransactionOptions options = tr.options();
        options.setReadSystemKeys();

        // we have to build the byte array and not using the Tuple layer APIs.
        //same to the output of the key value that we should not rely on the Tuple layer APIs.
        ByteBuffer bb = ByteBuffer.allocate("/status/json" + 2);
        bb.put((byte)0xff);
        bb.put((byte)0xff);
        bb.put("/status/json".getBytes(Charset.defaultCharset()));
        byte[] result = tr.get(bb.array()).join();

        try {
            String str = new String(result, "UTF-8");
            return str;
        } catch (Exception ex) {
            return null;
        }
    });
}