-
Notifications
You must be signed in to change notification settings - Fork 0
Network Binary Protocol
Current protocol version for 1.0-SNAPSHOT: 12. Look at compatibility for retro-compatibility.
<wiki:toc max_depth="3" />
The OrientDB binary protocol is the fastest way to interface a client application to an OrientDB Server instance. The aim of this page is to provide a starting point from which to build a language binding, maintaining high-performance.
If you'd like to develop a new binding, please take a look to the available ones before starting a new project from scratch
- C Language binding compatible with C++ and other languages that support C calls,
- OrientDB-PHP binary protocol,
- Ruby, publicly available soon
Also, check the available REST implementations.
Before starting, please note that:
- Record is an abstraction of Document. However, keep in mind that in OrientDB you can handle structures at a lower level than Documents. These include positional records, raw strings, raw bytes, etc. Look at Record for more information.
For more in-depth information please look at the Java classes:
- Client side: OStorageRemote.java
- Server side: ONetworkProtocolBinary.java
- Protocol constants: OChannelBinaryProtocol.java
(Since 0.9.24-SNAPSHOT Nov 25th 2010) Once connected, the server sends a short number (2 byte) containing the binary protocol number. The client should check that it supports that version of the protocol. Every time the protocol changes the version is incremented.
After the connection has been established, a client can Connect to the server or request the opening of a database Database Open. Currently, only TCP/IP raw sockets are supported. For this operation use socket APIs appropriate to the language you're using. After the Connect and Database Open all the client's requests are sent to the server until the client closes the socket. When the socket is closed, OrientDB Server instance frees resources the used for the connection.
The first operation following the socket-level connection must be one of:
- Connect to the server to work with the OrientDB Server instance
- Database Open to open an existing database
In both cases a Session-Id is sent back to the client. The server assigns a unique Session-Id to the client. This value must be used for all further operations against the server.
All the operations that follow the open/connect must contain, as the first parameter, the client Session-Id (as Integer, 4 bytes) and it will be sent back on completion of the request just after the result field.
NOTE: In order to create a new server-side connection, the client must send a negative number into the open/connect calls.
This Session-Id can be used into the client to keep track of the requests if it handles multiple session bound to the same connection. In this way the client can implement a sharing policy to save resources. This requires that the client implementation handle the response returned and dispatch it to the correct caller thread.
To make the development of a new client easier it's strongly suggested to activate debug mode on the binary channel. To activate this, edit the file orientdb-server-config.xml and configure the new parameter "network.binary.debug" on the "binary" or "distributed" listener. E.g.:
...
<listener protocol="distributed" port-range="2424-2430"
ip-address="127.0.0.1">
<parameters>
<parameter name="network.binary.debug" value="true" />
</parameters>
</listener>
...
In the log file (or the console if you have configured the orientdb-server-log.properties file) all the packets received will be printed.
This is the typical exchange of messages between client and server sides:
+------+ +------+
|Client| |Server|
+------+ +------+
| TCP/IP Socket connection |
+-------------------------->|
| DB_OPEN |
+-------------------------->|
| RESPONSE (+ SESSION-ID) |
+<--------------------------+
... ...
| REQUEST (+ SESSION-ID) |
+-------------------------->|
| RESPONSE (+ SESSION-ID) |
+<--------------------------+
... ...
| DB_CLOSE (+ SESSION-ID) |
+-------------------------->|
| TCP/IP Socket close |
+-------------------------->|
In explaining the network messages these conventions will be used:
- fields are bracketed by parenthesis and contain the name and the type separated by ':'. E.g.
(length:int)
The network protocol supports different types of information:
Type | Minimum length in bytes | Maximum length in bytes | Notes | Example |
---|---|---|---|---|
boolean | 1 | 1 | Single byte: 1 = true, 0 = false | 1 |
byte | 1 | 1 | Single byte, used to store small numbers and booleans | 1 |
short | 2 | 2 | Signed short type | 01 |
int | 4 | 4 | Signed integer type | 0001 |
long | 8 | 8 | Signed long type | 00000001 |
bytes | 4 | N | Used for binary data. The format is (length:int)[bytes)]((content:<length>) . Send -1 as NULL |
000511111 |
string | 4 | N | Used for text messages.The format is: (length:int)[bytes)]((content:<length>) . Send -1 as NULL |
0005Hello |
record | 2 | N | An entire record serialized. The format depends if a RID is passed or an entire record with its content. In case of null record then -2 as short is passed. In case of RID -3 is passes as short and then the RID: (-3:short)(cluster-id:short)(cluster-position:long) . In case of record: (0:short)(record-type:byte)(cluster-id:short)(cluster-position:long)(record-version:int)(record-content:bytes)
|
Documents are exchanged with the server component in a proprietary format (as a string) derived from JSON, but more compact. The string retrieved from the storage could be filled with spaces. This is due to the oversize feature if it is set. Just ignore the tailing spaces.
To know more about types look at http://code.google.com/p/orient/wiki/Types Supported types.
These are the rules:
-
Any string content must escape some characters:
-
" -> "
-
\ -> \
-
The class, if present, is at the begin and must end with
@
. E.g.Customer@
-
Each Field must be present with its name and value separated by
:
. E.g.name:"Barack"
-
Fields must be separated by
,
. E.g.name:"Barack",surname:"Obama"
-
All Strings must be enclosed by
"
character. E.g.city:"Rome"
-
All Binary content (like byte[must be encoded in Base64 and enclosed by underscore
_
character. E.g.buffer:AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGx
. Since v1.0rc7 -
Numbers (integer, long, short, byte, floats, double) are formatted as strings as ouput by the Java toString() method. No thousands separator must be used. The decimal separator is always
.
Starting from version 0.9.25, if the type is not integer, a suffix is used to distinguish the right type when unmarshalled: b=byte, s=short, l=long, f=float, d=double, c=BigDecimal (since 1.0rc8). E.g.salary:120.3f
orcode:124b
. -
Output of http://docs.oracle.com/javase/6/docs/api/java/lang/Float.html#toString(float) Floats)
-
Output of Doubles
-
Output of BigDecimal
-
Booleans are expressed as
true
andfalse
always in lower-case. They are recognized as boolean since the text has no double quote as is the case with strings -
Dates must be in the POSIX format (also called UNIX format: http://en.wikipedia.org/wiki/Unix_time). Are always stored as longs but end with:
-
the 't' character when it's DATETIME type (default in schema-less mode when a Date object is used). Datetime handles the maximum precision up to milliseconds. E.g.
lastUpdate:1296279468000t
is read as 2011-01-29 05:37:48 -
the 'a' character when it's DATE type. Date handles up to day as precision. E.g.
lastUpdate:1306281600000a
is read as 2011-05-25 00:00:00 (Available since 1.0rc2) -
Record Id (link) must be prefixed by
#
. A Record Id always has the format<cluster-id>:<cluster-position>
. E.g.location:#3:2
-
Embedded documents are enclosed by parenthesis
(
and)
characters. E.g.(name:"rules")
. Note: before SVN revision 2007 (0.9.24-snapshot) onlycharacters were used to begin and end the embedded document.*
-
Collections (array, list and sets) must be enclosed by
and
characters. E.g.[
#10:3,#10:4
and[There is a special case when use LINKSET type reported in detail in #Special_use_of_LINKSET_types Special use of LINKSET types section.
-
Maps (as a collection of entries with key/value) must be enclosed in
{
and} characters. E.g.
rules:{"database":2,"database.cluster.internal":2
} (NB. to set a value part of a key/value pair, set it to the text "null", without quotation marks. Eg.rules:{"database_name":"fred","database_alias":null
}) -
Null fields have an empty value part of the field. E.g.
salary_cloned:,salary:
{{{[Simple example (line breaks introduced so it's visible on this page):
Profile@nick:"ThePresident",follows:[],followers:[#10:5,#10:6],name:"Barack",surname:"Obama",
location:#3:2,invitedBy:,salary_cloned:,salary:120.3f
Complex example used in schema (line breaks introduced so it's visible on this page):
name:"ORole",id:0,defaultClusterId:3,clusterIds:[3],properties:[(name:"mode",type:17,offset:0,
mandatory:false,notNull:false,min:,max:,linkedClass:,
linkedType:,index:),(name:"rules",type:12,offset:1,mandatory:false,notNull:false,min:,
max:,linkedClass:,linkedType:17,index:)]
Other example of ORole that uses a map (line breaks introduced so it's visible on this page):
ORole@name:"reader",inheritedRole:,mode:0,rules:{"database":2,"database.cluster.internal":2,"database.cluster.orole":2,"database.cluster.ouser":2,
"database.class.*":2,"database.cluster.*":2,"database.query":2,"database.command":2,
"database.hook.record":2}
Each request has own format depending of the operation requested. The operation requested is indicated in the first byte:
- 1 byte for the operation. See [#Operation_types Operation types](@][,][:]*}}}) for the list
- 4 bytes for the Session-Id number as Integer
- N bytes = message content based on the operation type
Command | Value as byte | **Require authentication?** | Description | Can asynchronous? (no response) | Since |
---|---|---|---|---|---|
SHUTDOWN | 1 | Server (CONNECT operation) | Shut down the server | no | |
CONNECT | 2 | First operation to access to server commands | no | ||
DB_OPEN | 3 | First operation to access to the database | no | ||
DB_CREATE | 4 | Server (CONNECT operation) | no | ||
DB_CLOSE | 5 | Database (DB_OPEN operation) | no | ||
DB_EXIST | 6 | Server (CONNECT operation) | no | ||
DB_DELETE | 7 | Server (CONNECT operation) | no | ||
DB_SIZE | 8 | Database (DB_OPEN operation) | Returns the database size in bytes | no | 0.9.25 |
DB_COUNTRECORDS | 9 | Database (DB_OPEN operation) | Returns the total number of records in the database | no | 0.9.25 |
DATACLUSTER_ADD | 10 | Database (DB_OPEN operation) | no | ||
DATACLUSTER_REMOVE | 11 | Database (DB_OPEN operation) | no | ||
DATACLUSTER_COUNT | 12 | Database (DB_OPEN operation) | no | ||
DATACLUSTER_DATARANGE | 13 | Database (DB_OPEN operation) | no | ||
DATASEGMENT_ADD | 20 | Database (DB_OPEN operation) | no | ||
DATASEGMENT_REMOVE | 21 | Database (DB_OPEN operation) | no | ||
RECORD_LOAD | 30 | Database (DB_OPEN operation) | no | ||
RECORD_CREATE | 31 | Database (DB_OPEN operation) | yes | ||
RECORD_UPDATE | 32 | Database (DB_OPEN operation) | yes | ||
RECORD_DELETE | 33 | Database (DB_OPEN operation) | yes | ||
COUNT | 40 | Database (DB_OPEN operation) | no | ||
COMMAND | 41 | Database (DB_OPEN operation) | no | ||
TX_COMMIT | 60 | Database (DB_OPEN operation) | no | ||
CONFIG_GET | 70 | Server (CONNECT operation) | no | ||
CONFIG_SET | 71 | Server (CONNECT operation) | no | ||
CONFIG_LIST | 72 | Server (CONNECT operation) | no | ||
DB_RELOAD | 73 | Database (DB_OPEN operation) | no |
Every request has a response unless the command supports the asynchronous mode (look at the table above).
- 1 byte: Success status of the request if succeeded or failed (0=OK, 1=ERROR)
- 4 bytes: Session-Id (Integer)
- N bytes: Message content depending on the operation requested
Every time the client sends a request, and the command is not in asynchronous mode (look at the table above), client must read the one-byte response status that indicates OK or ERROR. The rest of response bytes depends on this first byte.
* OK = 0;
* ERROR = 1;
OK response bytes are depends for every request type. ERROR response bytes sequence described below.
The format is: [The pairs {{{exception-class
and exception-message
continue while the following byte is 1. A 0 in this position indicates that no more data follows.
E.g. (parentheses are used here just to separate fields to make this easier to read: they are not present in the server response):
(1)(com.orientechnologies.orient.core.exception.OStorageException)(Can't open the storage 'demo')(0)
Example of 2 depth-levels exception: d32d0e78292ee88fa0dfad13c5617836
This section explains the request and response messages of all suported operations.
Shut down the server. Requires "shutdown" permission to be set in orientdb-server-config.xml file.
Request: (user-name:string)(user-password:string)
Response: empty
Typically the credentials are those of the OrientDB server administrator. This is not the same as the admin user for individual databases.
This is the first operation requested by the client when it needs to work with the server instance. It returns the session id of the client.
Request: (driver-name:string)(driver-version:string)(protocol-version:short)(client-id:string)(user-name:string)(user-password:string)
Response: (session-id:int)
Where:
- client's driver-name as string. Example: "OrientDB Java client"
- client's driver-version as string. Example: "1.0rc8-SNAPSHOT"
- client's protocol-version as short. Example: 7
- client's client-id as string. Can be null for clients. In clustered configuration is the distributed node ID as TCP host+port. Example: "10.10.10.10:2480"
- user-name as string. Example: "root"
- user-password as string. Example: "kdsjkkasjad" Typically the credentials are those of the OrientDB server administrator. This is not the same as the admin user for individual databases. It returns the #Session-Id Session-Id to being reused for all the next calls.
This is the first operation the client should call. It opens a database on the remote OrientDB Server. Returns the Session-Id to being reused for all the next calls and the list of configured clusters.
Request: (driver-name:string)(driver-version:string)(protocol-version:short)(client-id:string)(database-name:string)(database-type:string)(user-name:string)(user-password:string)
Response: (session-id:int)(num-of-clusters:short)[(cluster-name:string)(cluster-id:short)(cluster-type:string)(cluster-dataSegmentId:short)](cluster-config:bytes)
Where:
- client's driver-name as string. Example: "OrientDB Java client"
- client's driver-version as string. Example: "1.0rc8-SNAPSHOT"
- client's protocol-version as short. Example: 7
- client's client-id as string. Can be null for clients. In clustered configuration is the distributed node ID as TCP host+port. Example: "10.10.10.10:2480"
- database-name as string. Example: "demo"
- database-type as string, can be 'document' or 'graph' (since version 8). Example: "document"
- user-name as string. Example: "admin"
- user-password as string. Example: "admin"
- cluster-config is always null unless you're running in a server clustered configuration.
Creates a database in the remote OrientDB server instance
Request: (database-name:string)(database-type:string)(storage-type:string)
Response: empty
Where:
- database-name as string. Example: "demo"
- database-type as string, can be 'document' or 'graph' (since version 8). Example: "document"
- storage-type can be one of the supported types:
- local, as a persistent database
- memory, as a volatile database NB. It doesn't make sense to use "remote" in this context
Closes the database and the network connection to the OrientDB Server instance. No return is expected. The socket is also closed.
Request: empty
Response: no response, the socket is just closed at server side
Asks if a database exists in the OrientDB Server instance. It returns true (non-zero) or false (zero).
Request: (database-name:string) <-- before 1.0rc1 this was empty
Response: (result:byte)
Reloads database information. Available since 1.0rc4.
Request: empty
Response:(num-of-clusters:short)[(cluster-name:string)(cluster-id:short)(cluster-type:string)(cluster-dataSegmentId:short)]
Removes a database from the OrientDB Server instance. It returns nothing if the database has been deleted or throws a OStorageException if the database doesn't exists.
Request: (database-name:string)
Response: empty
Asks for the size of a database in the OrientDB Server instance.
Request: empty
Response: (size:long)
Asks for the number of records in a database in the OrientDB Server instance.
Request: empty
Response: (count:long)
Add a new data cluster.
Request: (type:string)(name:string)(location:string)(datasegment-name:string)
In all cases:
Response: (new-cluster:short)
Where: type is one of "PHYSICAL" or "MEMORY".
Remove a cluster.
Request: (cluster-number:short)
Response: (delete-on-clientside:byte)
Where:
- delete-on-clientside can be 1 if the cluster has been successfully removed and the client has to remove too, otherwise 0
Returns the number of records in one or more clusters.
Request: (cluster-count:short)(cluster-number:short)*
Response: (records-in-clusters:long)
Where:
- cluster-count the number of requested clusters
- cluster-number the cluster id of each single cluster
- records-in-clusters is the total number of records found in the requested clusters
Request the record count for clusters 5, 6 and 7. Note the "03" at the beginning to tell you're passing 3 cluster ids (as short each). 1,000 as long (8 bytes) is the answer.
Request: 03050607
Response: 00001000
Returns the range of record ids for a cluster.
Request: (cluster-number:short)
Response: (begin:long)(end:long)
Request the range for cluster 7. The range 0-1,000 is returned in the response as 2 longs (8 bytes each).
Request: 07
Response: 0000000000001000
Add a new data segment.
Request: (name:string)(location:string)
In all cases:
Response: (new-datasegment-id:int)
Drop a data segment.
Request: (name:string)
In all cases:
Response: (succeeded:boolean)
Where:
- succeeded, is true if the data segment has been removed, otherwise false
Load a record by RecordID, according to a fetch plan
Request: (cluster-id:short)(cluster-position:long)(fetch-plan:string)(ignore-cache:byte)
Response: [(payload-status:byte)[(record-content:bytes)(record-version:int)(record-type:byte)]*]+
Where:
- fetch-plan, the fetch plan to use or an empty string
- ignore-cache, tells if the cache must be ignored: 1 = ignore the cache, 0 = not ignore. since protocol v.9 (introduced in release 1.0rc9)
- payload-status can be:
- 0: no records remain to be fetched
- 1: a record is returned as resultset
- 2: a record is returned as pre-fetched to be loaded in client's cache only. It's not part of the result set but the client knows that it's available for later access. This value is not currently used.
- record-type is
- 'b': raw bytes
- 'f': flat data
- 'd': document
Create a new record. Returns the position in the cluster of the new record. New records can have version > 0 (since v1.0) in case the RID has been recycled.
Request: (datasegment-id:int)(cluster-id:short)(record-content:bytes)(record-type:byte)(mode:byte)
Response: (cluster-position:long)(record-version:int)
Where:
- datasegment-id the segment id to store the data (since version 10 - 1.0-SNAPSHOT). -1 Means default one.
- record-type is:
- 'b': raw bytes
- 'f': flat data
- 'd': document
and mode is:
- 0 = synchronous (default mode waits for the answer)
- 1 = asynchronous (don't need an answer)
Update a record. Returns the new record's version.
Request: (cluster-id:short)(cluster-position:long)(record-content:bytes)(record-version:int)(record-type:byte)(mode:byte)
Response: (record-version:int)
Where record-type is:
- 'b': raw bytes
- 'f': flat data
- 'd': document
and record-version policy is:
- '-1': Document update, version increment, no version control.
- '-2': Document update, no version control nor increment.
- '-3': Used internal in transaction rollback (version decrement).
- '>-1': Standard document update (version control).
and mode is:
- 0 = synchronous (default mode waits for the answer)
- 1 = asynchronous (don't need an answer)
Delete a record by its RecordID. During the optimistic transaction the record will be deleted only if the versions match. Returns true if has been deleted otherwise false.
Request: (cluster-id:short)(cluster-position:long)(record-version:int)(mode:byte)
Response: (payload-status:byte)
Where:
- mode is:
- 0 = synchronous (default mode waits for the answer)
- 1 = asynchronous (don't need an answer)
- payload-status returns the number of records deleted: 1 if the record has been successfully deleted, otherwise 0.
Returns the number of records contained in the requested cluster.
Request: (cluster-name:string)
Response: (record-count:long)
Executes remote commands:
Request: (mode:byte)(class-name:string)(command-payload)
Response: [(payload-status:byte)[(content:?)]*]+
Where:
- mode can be 'a' for asynchronous mode and 's' for synchronous mode
- class-name is the class name of the command implementation. There are short form for the most common commands:
-
q stands for query as idempotent command. It's like passing
com.orientechnologies.orient.core.sql.query.OSQLSynchQuery
-
c stands for command as non-idempotent command (insert, update, etc). It's like passing
com.orientechnologies.orient.core.sql.OCommandSQL
-
s stands for script. It's like passing
com.orientechnologies.orient.core.command.script.OCommandScript
. Script commands by using any supported server-side scripting like Javascript command. Since v1.0. -
any other values is the class name. The command will be created via reflection using the default constructor and invoking the
fromStream()
method against it - command-payload is the command's serialized payload (see below SQL command payload)
- payload-status will be:
- 0: no records remain to be fetched
- 1: a record is returned as a resultset
- 2: a record is returned as pre-fetched to be loaded in client's cache only. It's not part of the result set but the client knows that it's available for later access.
- 'n', means null result
- 'r', means single record returned
- 'a', serialized result
- 'l', collection of records
- content, depends on the payload-status.
Payload is:
(text:string)(non-text-limit:int)[(fetchplan:string)](serialized-params:bytes)
- text: text of the query
- non-text-limit : Limit can be set in query's text, or here. This field had priority. Send -1 to use limit from query's text
- fetchplan: used only for select queries, otherwise empty
- serialized-params: used to parametrise query. Send 0:int to disable
Payload is:
(language:string)(text:string)(non-text-limit:int)[(fetchplan:string)](serialized-params:bytes)
- language: name of the language to use. The language must be recognized on the OrientDB Server. Usually is "Javascript" that it's bundled with the JVM
- text : the text containing the script to be executed
- non-text-limit : Limit can be set in query's text, or here. This field had priority. Send -1 to use limit from query's text
- fetchplan: used only for select queries, otherwise empty
- serialized-params: used to parametrise query. Send 0:int to disable
Commits a transaction. This operation flushes all the pending changes to the server side.
Request: (tx-id:int)(using-tx-log:byte)[(operation-type:byte)(cluster-id:short)(cluster-position:long)(record-type:byte)<record-content>]*(0-byte indicating end-of-records)
Response: (created-record-count:int)[(client-specified-cluster-id:short)(client-specified-cluster-position:long)(created-cluster-id:short)(created-cluster-position:long)]*(updated-record-count:int)[(updated-cluster-id:short)(updated-cluster-position:long)(new-record-version:int)]*
Where:
- tx-id is the Transaction's Id
- use-tx-log tells if the server must use the Transaction Log to recover the transaction. 1 = true, 0 = false
- operation-type can be:
- 1, for UPDATES
- 2, for DELETES
- 3, for CREATIONS
- record-content depends on the operation type:
- For UPDATED (1):
(original-record-version:int)(record-content:bytes)
- For DELETED (2):
(original-record-version:int)
- For CREATED (3):
(record-content:bytes)
This response contains two parts: a map of 'temporary' client-generated record ids to 'real' server-provided record ids for each CREATED record, and a map of UPDATED record ids to update record-versions.
Look at Optimistic Transaction to know how temporary RecordIDs are managed.
Starting from 1.0rc8-SNAPSHOT OrientDB can transform collections of links from the classic mode:
{{{[to:
(ORIDs@pageSize:16,root:#2:6)
For more information look at the announcement of this new feature: https://groups.google.com/d/topic/orient-database/QF52JEwCuTM/discussion
In practice to optimize cases with many relationships/edges the collection is transformed in a mvrb-tree. This is because the embedded object. In that case the important thing is the link to the root node of the balanced tree.
You can disable this behaviour by setting
mvrbtree.ridBinaryThreshold = -1
Where mvrbtree.ridBinaryThreshold is the threshold where OrientDB will use the tree instead of plain collection (as before). -1 means "hey, never use the new mode but leave all as before".
To improve performance this structure is managed in binary form. Below how is made: b8c64fea51e84fc68a92c017a44f9f94
Where:
- TREE SIZE as signed integer (4 bytes) containing the size of the tree. Only the root node has this value updated, so to know the size of the collection you need to load the root node and get this field. other nodes can contain not updated values because upon rotation of pieces of the tree (made during tree rebalancing) the root can change and the old root will have the "old" size as dirty.
- NODE SIZE as signed integer (4 bytes) containing number of entries in this node. It's always <= to the page-size defined at the tree level and equals for all the nodes. By default page-size is 16 items
- COLOR as 1 byte containing 1=Black, 0=Red. To know more about the meaning of this look at http://en.wikipedia.org/wiki/Red%E2%80%93black_tree Red-Black Trees
- PARENT RID as RID (10 bytes) of the parent node record
- LEFT RID as RID (10 bytes) of the left node record
- RIGHT RID as RID (10 bytes) of the right node record
- RID LIST as the list of RIDs containing the references to the records. This is pre-allocated to the configured page-size. Since each RID takes 10 bytes, a page-size of 16 means 16 x 10bytes = 160bytes
The size of the tree-node on disk (and memory) is fixed to avoid fragmentation. To compute it: 39 bytes + 10 * PAGE-SIZE bytes. For a page-size = 16 you'll have 39 + 160 = 199 bytes.
- DB_OPEN returns the dataSegmentId foreach cluster
- RECORD_CREATE always returns the record version. This was necessary because new records could have version > 0 to avoid MVCC problems on RID recycle
Current release of OrientDB server supports older client versions.
- version 11: 100% compatible. 1.0-SNAPSHOT
- version 10: 100% compatible. 1.0rc9-SNAPSHOT
- version 9: 100% compatible. 1.0rc9-SNAPSHOT
- version 8: 100% compatible. 1.0rc9-SNAPSHOT
- version 7: 100% compatible. 1.0rc7-SNAPSHOT - 1.0rc8
- version 6: 100% compatible. Before 1.0rc7-SNAPSHOT
- < version 6: not compatible