/* -*- mode: systemtap; -*-
 *
 *     Copyright 2017 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/*
 * SystemTap tapset to make it easier to trace libcouchbase
 *
 * All probes provided by libcouchbase can be listed using following command:
 *
 * stap -L 'process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("*")'
 */


/**
 * Convert opcode from couchbase KV protocol to string representation
 */
function libcouchbase_opcode:string(opcode:long)
{
    if (opcode == 0x00) return "GET"
    else if (opcode == 0x01) return "SET"
    else if (opcode == 0x02) return "ADD"
    else if (opcode == 0x03) return "REPLACE"
    else if (opcode == 0x04) return "DELETE"
    else if (opcode == 0x05) return "INCREMENT"
    else if (opcode == 0x06) return "DECREMENT"
    else if (opcode == 0x08) return "FLUSH"
    else if (opcode == 0x09) return "GETQ"
    else if (opcode == 0x0a) return "NOOP"
    else if (opcode == 0x0b) return "VERSION"
    else if (opcode == 0x0e) return "APPEND"
    else if (opcode == 0x0f) return "PREPEND"
    else if (opcode == 0x10) return "STAT"
    else if (opcode == 0x1b) return "VERBOSITY"
    else if (opcode == 0x1c) return "TOUCH"
    else if (opcode == 0x1d) return "GAT"
    else if (opcode == 0x1f) return "HELLO"
    else if (opcode == 0x20) return "SASL_LIST_MECHS"
    else if (opcode == 0x21) return "SASL_AUTH"
    else if (opcode == 0x22) return "SASL_STEP"
    else if (opcode == 0x83) return "GET_REPLICA"
    else if (opcode == 0x89) return "SELECT_BUCKET"
    else if (opcode == 0x91) return "OBSERVE_SEQNO"
    else if (opcode == 0x92) return "OBSERVE"
    else if (opcode == 0x94) return "GET_LOCKED"
    else if (opcode == 0x95) return "UNLOCK_KEY"
    else if (opcode == 0xb5) return "GET_CLUSTER_CONFIG"
    else if (opcode == 0xc5) return "SUBDOC_GET"
    else if (opcode == 0xc6) return "SUBDOC_EXISTS"
    else if (opcode == 0xc7) return "SUBDOC_DICT_ADD"
    else if (opcode == 0xc8) return "SUBDOC_DICT_UPSERT"
    else if (opcode == 0xc9) return "SUBDOC_DELETE"
    else if (opcode == 0xca) return "SUBDOC_REPLACE"
    else if (opcode == 0xcb) return "SUBDOC_ARRAY_PUSH_LAST"
    else if (opcode == 0xcc) return "SUBDOC_ARRAY_PUSH_FIRST"
    else if (opcode == 0xcd) return "SUBDOC_ARRAY_INSERT"
    else if (opcode == 0xce) return "SUBDOC_ARRAY_ADD_UNIQUE"
    else if (opcode == 0xcf) return "SUBDOC_COUNTER"
    else if (opcode == 0xd0) return "SUBDOC_MULTI_LOOKUP"
    else if (opcode == 0xd1) return "SUBDOC_MULTI_MUTATION"
    else if (opcode == 0xd2) return "SUBDOC_GET_COUNT"
    else if (opcode == 0xfe) return "GET_ERROR_MAP"
    else return "UNKNOWN"
}

/**
 * Convert HTTP request type to string representation
 */
function libcouchbase_http_type:string(type:long)
{
    if (type == 0) return "VIEW"
    else if (type == 1) return "MANAGEMENT"
    else if (type == 2) return "RAW"
    else if (type == 3) return "N1QL"
    else if (type == 4) return "FTS"
    else if (type == 5) return "CBAS"
    else return "UNKNOWN"
}

/**
 * Convert HTTP request method to string representation
 */
function libcouchbase_http_method:string(method:long)
{
    if (method == 0) return "GET"
    else if (method == 1) return "POST"
    else if (method == 2) return "PUT"
    else if (method == 3) return "DELETE"
    else return "UNKNOWN"
}

/**
 * probe libcouchbase.kv.get.begin - start of GET/GETL/GAT operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @vbucket: number of partition
 * @opcode: opcode, see memcached/protocol_binary.h
 * @key: document id
 * @expiration: document expiration (0 when should not expire)
 *
 * Example:
 *
 *   probe libcouchbase.kv.get.begin {
 *     printf("[%p] opcode: %s, vbucket: %d, key: %s\n",
 *         lcb, libcouchbase_opcode(opcode), vbucket, key)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc get foo"
 *   foo                  CAS=0x150268ca90610000, Flags=0x0, Size=13, Datatype=0x01(JSON)
 *   {"foo":"bar"}
 *   [0xf20d90] opcode: GET, vbucket: 115, key: foo
 */
probe libcouchbase.kv.get.begin =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("get_begin")
{
    lcb = $arg1
    opaque = $arg2
    vbucket = $arg3
    opcode = $arg4
    key = user_string_n($arg5, $arg6)
    expiration = $arg7
}

/**
 * probe libcouchbase.kv.get.end - end of GET/GETL/GAT operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @opcode: opcode, see memcached/protocol_binary.h
 * @latency_ns: time from schedule to dispatch of the command
 * @rc: return code from the library see libcouchbase/error.h
 * @key: document id
 * @bytes: document body
 * @flags: document flags
 * @cas: document CAS
 * @datatype: document datatype, see memcached/protocol_binary.h
 *
 * Example:
 *
 *   probe libcouchbase.kv.get.end {
 *     printf("[%p] opcode: %s, rc: %d, cas: 0x%x, key: %s, value: %s\n",
 *         lcb, libcouchbase_opcode(opcode), rc, cas, key, bytes)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc get foo"
 *   foo                  CAS=0x150268ca90610000, Flags=0x0, Size=13, Datatype=0x01(JSON)
 *   {"foo":"bar"}
 *   [0x1b58dd0] opcode: GET, rc: 0, cas: 0x150268ca90610000, key: foo, value: {"foo":"bar"}
 */
probe libcouchbase.kv.get.end =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("get_end")
{
    lcb = $arg1
    opaque = $arg2
    opcode = $arg3
    latency_ns = $arg4
    rc = $arg5
    key = user_string_n($arg6, $arg7)
    bytes = user_string_n($arg8, $arg9)
    flags = $arg10
    cas = $arg11
    datatype = $arg12
}

/**
 * probe libcouchbase.kv.arithmetic.begin - start of INCR/DECR operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @vbucket: number of partition
 * @opcode: opcode, see memcached/protocol_binary.h
 * @key: document id
 * @delta: the 64 bit value to change the counter
 * @initial: the value to use, when document is not exist
 * @expiration: document expiration (0 when should not expire)
 *
 * Example:
 *
 *   probe libcouchbase.kv.arithmetic.begin {
 *     printf("[%p] opcode: %s, delta: %d, initial: %d, key: %s\n",
 *         lcb, libcouchbase_opcode(opcode), delta, initial, key)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc incr --initial 42 --delta 3 cnt"
 *   cnt                 Current value is 42. CAS=0x15026eea18850000
 *   [0x117bdd0] opcode: INCREMENT, delta: 3, initial: 42, key: cnt
 */
probe libcouchbase.kv.arithmetic.begin =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("arithmetic_begin")
{
    lcb = $arg1
    opaque = $arg2
    vbucket = $arg3
    opcode = $arg4
    key = user_string_n($arg5, $arg6)
    delta = $arg7
    initial = $arg8
    expiration = $arg9
}

/**
 * probe libcouchbase.kv.arithmetic.end - end of INCR/DECR operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @opcode: opcode, see memcached/protocol_binary.h
 * @latency_ns: time from schedule to dispatch of the command
 * @rc: return code from the library see libcouchbase/error.h
 * @key: document id
 * @value: current value of the counter (as 64bit number)
 * @cas: document CAS
 *
 * Example:
 *
 *   probe libcouchbase.kv.arithmetic.end {
 *     printf("[%p] opcode: %s, rc: %d, cas: 0x%x, key: %s, value: %d\n",
 *         lcb, libcouchbase_opcode(opcode), rc, cas, key, value)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc decr --delta 3 cnt"
 *   cnt                 Current value is 42. CAS=0x15026f100ece0000
 *   [0x6cf0b0] opcode: DECREMENT, rc: 0, cas: 0x15026f100ece0000, key: cnt, value: 42
 */
probe libcouchbase.kv.arithmetic.end =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("arithmetic_end")
{
    lcb = $arg1
    opaque = $arg2
    opcode = $arg3
    latency_ns = $arg4
    rc = $arg5
    key = user_string_n($arg6, $arg7)
    value = $arg8
    cas = $arg9
}

/**
 * probe libcouchbase.kv.remove.begin - start of DELETE operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @vbucket: number of partition
 * @opcode: opcode, see memcached/protocol_binary.h
 * @key: document id
 *
 * Example:
 *
 *   probe libcouchbase.kv.remove.begin {
 *     printf("[%p] opcode: %s, key: %s\n",
 *         lcb, libcouchbase_opcode(opcode), key)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc rm cnt"
 *   cnt                 Deleted. CAS=0x15026f2ec2c90000
 *   [0x9280c0] opcode: DELETE, key: cnt
 */
probe libcouchbase.kv.remove.begin =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("remove_begin")
{
    lcb = $arg1
    opaque = $arg2
    vbucket = $arg3
    opcode = $arg4
    key = user_string_n($arg5, $arg6)
}

/**
 * probe libcouchbase.kv.remove.end - end of DELETE operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @opcode: opcode, see memcached/protocol_binary.h
 * @latency_ns: time from schedule to dispatch of the command
 * @rc: return code from the library see libcouchbase/error.h
 * @key: document id
 * @cas: document CAS
 *
 * Example:
 *
 *   probe libcouchbase.kv.remove.end {
 *     printf("[%p] opcode: %s, rc: %d, cas: 0x%x, key: %s\n",
 *         lcb, libcouchbase_opcode(opcode), rc, cas, key)
 *   }

 *
 *   $ stap  test.stp  -c "cbc rm cnt"
 *   cnt                 Deleted. CAS=0x15026f2ec2c90000
 *   [0x9280c0] opcode: DELETE, rc: 0, cas: 0x15026f2ec2c90000, key: cnt
 */
probe libcouchbase.kv.remove.end =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("remove_end")
{
    lcb = $arg1
    opaque = $arg2
    opcode = $arg3
    latency_ns = $arg4
    rc = $arg5
    key = user_string_n($arg6, $arg7)
    cas = $arg8
}

/**
 * probe libcouchbase.kv.store.begin - start of SET/ADD/REPLACE/APPEND/PREPEND operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @vbucket: number of partition
 * @opcode: opcode, see memcached/protocol_binary.h
 * @key: document id
 * @bytes: document body
 * @flags: document flags
 * @cas: document CAS
 * @datatype: document datatype, see memcached/protocol_binary.h
 * @expiration: document expiration (0 when should not expire)
 *
 * Example:
 *
 *   probe libcouchbase.kv.store.begin {
 *     printf("[%p] opcode: %s, key: %s, value: %s, expiration: %d\n",
 *         lcb, libcouchbase_opcode(opcode), key, bytes, expiration)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc cp -e 30 foo"
 *   foo                 Stored. CAS=0x15026f8450790000
 *   [0x7e0070] opcode: SET, key: foo, value: {"foo":"bar"}, expiration: 30
 */
probe libcouchbase.kv.store.begin =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("store_begin")
{
    lcb = $arg1
    opaque = $arg2
    vbucket = $arg3
    opcode = $arg4
    key = user_string_n($arg5, $arg6)
    bytes = user_string_n($arg7, $arg8)
    flags = $arg9
    cas = $arg10
    datatype = $arg11
    expiration = $arg12
}

/**
 * probe libcouchbase.kv.store.end - end of SET/ADD/REPLACE/APPEND/PREPEND operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @opcode: opcode, see memcached/protocol_binary.h
 * @latency_ns: time from schedule to dispatch of the command
 * @rc: return code from the library see libcouchbase/error.h
 * @key: document id
 * @cas: document CAS
 *
 * Example:
 *
 *   probe libcouchbase.kv.store.end {
 *     printf("[%p] opcode: %s, rc: %d, cas: 0x%x, key: %s\n",
 *         lcb, libcouchbase_opcode(opcode), rc, cas, key)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc cp -e 30 foo"
 *   foo                 Stored. CAS=0x15026f8450790000
 *   [0x7e0070] opcode: SET, rc: 0, cas: 0x15026f8450790000, key: foo
 */
probe libcouchbase.kv.store.end =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("store_end")
{
    lcb = $arg1
    opaque = $arg2
    opcode = $arg3
    latency_ns = $arg4
    rc = $arg5
    key = user_string_n($arg6, $arg7)
    cas = $arg8
}

/**
 * probe libcouchbase.kv.unlock.begin - start of UNLOCK operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @vbucket: number of partition
 * @opcode: opcode, see memcached/protocol_binary.h
 * @key: document id
 *
 * Example:
 *
 *   probe libcouchbase.kv.unlock.begin {
 *     printf("[%p] opcode: %s, key: %s\n",
 *         lcb, libcouchbase_opcode(opcode), key)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc unlock foo 0x15028f7bafc20000"
 *   foo                  Unlocked
 *   [0x20d7100] opcode: UNLOCK_KEY, key: foo
 */
probe libcouchbase.kv.unlock.begin =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("unlock_begin")
{
    lcb = $arg1
    opaque = $arg2
    vbucket = $arg3
    opcode = $arg4
    key = user_string_n($arg5, $arg6)
}

/**
 * probe libcouchbase.kv.unlock.end - end of UNLOCK operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @opcode: opcode, see memcached/protocol_binary.h
 * @latency_ns: time from schedule to dispatch of the command
 * @rc: return code from the library see libcouchbase/error.h
 * @key: document id
 *
 * Example:
 *
 *   probe libcouchbase.kv.unlock.end {
 *     printf("[%p] opcode: %s, rc: %d, key: %s\n",
 *         lcb, libcouchbase_opcode(opcode), rc, key)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc unlock foo 0x15028f7bafc20000"
 *   foo                  Unlocked
 *   [0x20d7100] opcode: UNLOCK_KEY, rc: 0, key: foo
 */
probe libcouchbase.kv.unlock.end =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("unlock_end")
{
    lcb = $arg1
    opaque = $arg2
    opcode = $arg3
    latency_ns = $arg4
    rc = $arg5
    key = user_string_n($arg6, $arg7)
}

/**
 * probe libcouchbase.kv.touch.begin - start of TOUCH operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @vbucket: number of partition
 * @opcode: opcode, see memcached/protocol_binary.h
 * @key: document id
 * @expiration: document expiration (0 when should not expire)
 *
 * Example:
 *
 *   probe libcouchbase.kv.touch.begin {
 *     printf("[%p] opcode: %s, key: %s, expiration: %d\n",
 *         lcb, libcouchbase_opcode(opcode), key, expiration)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc touch -e 10 foo"
 *   foo                 Touched. CAS=0x150290b309ad0000
 *   [0x141edb0] opcode: TOUCH, rc: 0, cas: 0x150290b309ad0000, key: foo
 */
probe libcouchbase.kv.touch.begin =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("touch_begin")
{
    lcb = $arg1
    opaque = $arg2
    vbucket = $arg3
    opcode = $arg4
    key = user_string_n($arg5, $arg6)
    expiration = $arg7
}

/**
 * probe libcouchbase.kv.touch.end - end of TOUCH operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @opcode: opcode, see memcached/protocol_binary.h
 * @latency_ns: time from schedule to dispatch of the command
 * @rc: return code from the library see libcouchbase/error.h
 * @key: document id
 * @cas: document CAS
 *
 * Example:
 *
 *   probe libcouchbase.kv.touch.end {
 *     printf("[%p] opcode: %s, rc: %d, cas: 0x%x, key: %s\n",
 *         lcb, libcouchbase_opcode(opcode), rc, cas, key)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc touch -e 10 foo"
 *   foo                 Touched. CAS=0x150290b309ad0000
 *   [0x141edb0] opcode: TOUCH, rc: 0, cas: 0x150290b309ad0000, key: foo
 */
probe libcouchbase.kv.touch.end =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("touch_end")
{
    lcb = $arg1
    opaque = $arg2
    opcode = $arg3
    latency_ns = $arg4
    rc = $arg5
    key = user_string_n($arg6, $arg7)
    cas = $arg8
}

/*
 * probe libcouchbase.kv.observe.begin - start of OBSERVE operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @opcode: opcode, see memcached/protocol_binary.h
 * @bytes: pointer to payload (as long)
 * @nbytes: size of payload
 *
 * libcouchbase.observe.begin probe intended to be parsed in the handler.
 * the bytes argument is a blob with nbytes length:
 *
 * +---------+---------+------------+----
 * | 16 bits | 16 bits | nkey bytes | ...
 * +---------+---------+------------+----
 * | vbucket |   nkey  |    key     | ...
 * +---------+---------+------------+----
 *
 * Example:
 *
 *   probe libcouchbase.kv.observe.begin {
 *     printf("[%p] opcode: %d, opaque: %d\n", lcb, libcouchbase_opcode(opcode), opaque)
 *     while (nbytes > 0) {
 *       vbucket = ntohs(user_uint16(bytes))
 *       nbytes -= 2
 *       bytes += 2
 *       nkey = ntohs(user_uint16(bytes))
 *       nbytes -= 2
 *       bytes += 2
 *       key = user_string_n(bytes, nkey)
 *       nbytes -= nkey
 *       bytes += nkey
 *       printf("    vbucket: %d, nkey: %d, key: %s\n", vbucket, nkey, key)
 *     }
 *   }
 *
 *
 * The following command executed on cluster with 4 nodes, and replication factor 3.
 *
 *   $ stap  test.stp  -c "cbc observe foo bar"
 *   foo                  [Replica] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Replica] Status=0x1, CAS=0x1502951fe0040000
 *   foo                  [Replica] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Master] Status=0x1, CAS=0x1502951fe0040000
 *   foo                  [Replica] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Replica] Status=0x1, CAS=0x1502951fe0040000
 *   foo                  [Master] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Replica] Status=0x1, CAS=0x1502951fe0040000
 *   [0xb33dc0] opcode: OBSERVE, opaque: 0
 *      vbucket: 115, nkey: 3, key: foo
 *      vbucket: 767, nkey: 3, key: bar
 *   [0xb33dc0] opcode: OBSERVE, opaque: 1
 *      vbucket: 115, nkey: 3, key: foo
 *      vbucket: 767, nkey: 3, key: bar
 *   [0xb33dc0] opcode: OBSERVE, opaque: 2
 *      vbucket: 115, nkey: 3, key: foo
 *      vbucket: 767, nkey: 3, key: bar
 *   [0xb33dc0] opcode: OBSERVE, opaque: 3
 *      vbucket: 115, nkey: 3, key: foo
 *      vbucket: 767, nkey: 3, key: bar
 */
probe libcouchbase.kv.observe.begin =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("observe_begin")
{
    lcb = $arg1
    opaque = $arg2
    opcode = $arg4
    bytes = $arg5
    nbytes = $arg6
}

/**
 * probe libcouchbase.kv.observe.progress - intermediate response of OBSERVE operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @vbucket: number of partition
 * @opcode: opcode, see memcached/protocol_binary.h
 * @latency_ns: time from schedule to dispatch of the command
 * @rc: return code from the library see libcouchbase/error.h
 * @key: document id
 * @status: observe status: FOUND = 0x00, PERSISTED = 0x01, NOT_FOUND = 0x80
 * @master: whether response from master node (zero if from replica)
 * @ttp: time to persist
 * @ttr: time to replicate
 *
 * Example:
 *
 *   probe libcouchbase.kv.observe.progress {
 *     printf("[%p] opcode: %s, opaque: %d, rc: %d, key: %s, status: %d, master: %s\n",
 *         lcb, libcouchbase_opcode(opcode), opaque, rc, key, status, master ? "true" : "false")
 *   }
 *
 *
 * The following command executed on cluster with 4 nodes, and replication factor 3.
 *
 *   $ stap  test.stp  -c "cbc observe foo bar"
 *   foo                  [Replica] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Replica] Status=0x1, CAS=0x1502951fe0040000
 *   foo                  [Replica] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Master] Status=0x1, CAS=0x1502951fe0040000
 *   foo                  [Replica] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Replica] Status=0x1, CAS=0x1502951fe0040000
 *   foo                  [Master] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Replica] Status=0x1, CAS=0x1502951fe0040000
 *   [0xb33dc0] opcode: OBSERVE, opaque: 0, rc: 0, key: foo, status: 1, master: false
 *   [0xb33dc0] opcode: OBSERVE, opaque: 0, rc: 0, key: bar, status: 1, master: false
 *   [0xb33dc0] opcode: OBSERVE, opaque: 3, rc: 0, key: foo, status: 1, master: false
 *   [0xb33dc0] opcode: OBSERVE, opaque: 3, rc: 0, key: bar, status: 1, master: true
 *   [0xb33dc0] opcode: OBSERVE, opaque: 1, rc: 0, key: foo, status: 1, master: false
 *   [0xb33dc0] opcode: OBSERVE, opaque: 1, rc: 0, key: bar, status: 1, master: false
 *   [0xb33dc0] opcode: OBSERVE, opaque: 2, rc: 0, key: foo, status: 1, master: true
 *   [0xb33dc0] opcode: OBSERVE, opaque: 2, rc: 0, key: bar, status: 1, master: false
 */
probe libcouchbase.kv.observe.progress =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("observe_progress")
{
    lcb = $arg1
    opaque = $arg2
    opcode = $arg3
    latency_ns = $arg4
    rc = $arg5
    key = user_string_n($arg6, $arg7)
    cas = $arg8
    status = $arg9
    master = $arg10
    ttp = $arg11
    ttr = $arg12
}

/**
 * probe libcouchbase.kv.observe.end - end of OBSERVE operation
 *
 * @lcb: client instance
 * @opaque: unique number for this request (visible on network, returned by server back)
 * @opcode: opcode, see memcached/protocol_binary.h
 * @latency_ns: time from schedule to dispatch of the command
 * @rc: return code from the library see libcouchbase/error.h
 *
 * Example:
 *
 *   probe libcouchbase.kv.observe.end {
 *     printf("[%p] opcode: %s, opaque, rc: %d\n",
 *         lcb, libcouchbase_opcode(opcode), opaque, rc)
 *   }
 *
 *
 * The following command executed on cluster with 4 nodes, and replication factor 3.
 *
 *   $ stap  test.stp  -c "cbc observe foo bar"
 *   foo                  [Replica] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Replica] Status=0x1, CAS=0x1502951fe0040000
 *   foo                  [Replica] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Master] Status=0x1, CAS=0x1502951fe0040000
 *   foo                  [Replica] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Replica] Status=0x1, CAS=0x1502951fe0040000
 *   foo                  [Master] Status=0x1, CAS=0x1502952004ed0000
 *   bar                  [Replica] Status=0x1, CAS=0x1502951fe0040000
 *   [0xb33dc0] opcode: OBSERVE, opaque: 0, rc: 0
 *   [0xb33dc0] opcode: OBSERVE, opaque: 3, rc: 0
 *   [0xb33dc0] opcode: OBSERVE, opaque: 1, rc: 0
 *   [0xb33dc0] opcode: OBSERVE, opaque: 2, rc: 0
 */
probe libcouchbase.kv.observe.end =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("observe_end")
{
    lcb = $arg1
    opaque = $arg2
    opcode = $arg3
    latency_ns = $arg4
    rc = $arg5
}

/**
 * probe libcouchbase.http.begin - start of HTTP request
 *
 * @lcb: client instance
 * @req: pointer to request
 * @type: type of request, see enum lcb_http_type_t in libcouchbase/couchbase.h
 * @method: HTTP method of request, see enum lcb_http_method_t in libcouchbase/couchbase.h
 * @url: request URL (including schema, host and port)
 * @host: target hostname
 * @port: target port
 *
 * Example:
 *
 *   probe libcouchbase.http.begin {
 *     printf("[%p] req: %p, type: %s, url: %s, host: %s, port: %s\n",
 *         lcb, req, libcouchbase_http_type(type), url, host, port)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc n1ql 'select 1'"
 *   ---> Encoded query: {"statement":"select 1"}
 *
 *   {"$1":1},
 *   ---> Query response finished
 *   {
 *   "requestID": "c36facda-b37e-43b5-a958-7f31afb8468f",
 *   "signature": {"$1":"number"},
 *   "results": [
 *   ],
 *   "status": "success",
 *   "metrics": {"elapsedTime": "380.883µs","executionTime": "360.955µs","resultCount": 1,"resultSize": 8}
 *   }
 *
 *   [0x1af6de0] req: 0x1b12250, type: N1QL, url: http://192.168.1.104:8093/query/service, host: 192.168.1.104, port: 8093
 */
probe libcouchbase.http.begin =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("http_begin")
{
    lcb = $arg1
    req = $arg2
    type = $arg3
    method = $arg4
    url = user_string($arg5)
    host = user_string($arg6)
    port = user_string($arg7)
}

/**
 * probe libcouchbase.http.end - start of HTTP request
 *
 * @lcb: client instance
 * @req: pointer to request
 * @type: type of request, see enum lcb_http_type_t in libcouchbase/couchbase.h
 * @method: HTTP method of request, see enum lcb_http_method_t in libcouchbase/couchbase.h
 * @url: request URL (including schema, host and port)
 * @host: target hostname
 * @port: target port
 * @rc: return code from the library see libcouchbase/error.h
 * @status: HTTP status code (number)
 * @latency_ns: time from schedule to dispatch of the request
 *
 * Example:
 *
 *   probe libcouchbase.http.end {
 *     printf("[%p] req: %p, type: %s, url: %s, host: %s, port: %s, rc: %d, status: %d\n",
 *         lcb, req, libcouchbase_http_type(type), url, host, port, rc, status)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc n1ql 'select 1'"
 *   ---> Encoded query: {"statement":"select 1"}
 *
 *   {"$1":1},
 *   ---> Query response finished
 *   {
 *   "requestID": "c36facda-b37e-43b5-a958-7f31afb8468f",
 *   "signature": {"$1":"number"},
 *   "results": [
 *   ],
 *   "status": "success",
 *   "metrics": {"elapsedTime": "380.883µs","executionTime": "360.955µs","resultCount": 1,"resultSize": 8}
 *   }
 *
 *   [0x1af6de0] req: 0x1b12250, type: N1QL, url: http://192.168.1.104:8093/query/service, host: 192.168.1.104, port: 8093, rc: 0, status: 200
 */
probe libcouchbase.http.end =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("http_end")
{
    lcb = $arg1
    req = $arg2
    type = $arg3
    method = $arg4
    url = user_string($arg5)
    host = user_string($arg6)
    port = user_string($arg7)
    rc = $arg8
    status = $arg9
    latency_us = $arg10
}

/**
 * probe libcouchbase.config.new - new configuration applied to the lcb_INSTANCE * instance
 *
 * @lcb: client instance
 * @revid: configuration revision
 * @bucket_name: name of the bucket
 * @bucket_uuid: UUID of the bucket
 *
 * Example:
 *
 *   probe libcouchbase.config.new {
 *     printf("[%p] NEW CONFIG revid: %d, bucket: %s, uuid: %s\n",
 *         lcb, revid, bucket_name, bucket_uuid)
 *   }
 *
 *
 *   $ stap  test.stp  -c "cbc hash foo"
 *   foo: [vBucket=115, Index=0] Server: 127.0.0.1:11210, CouchAPI: http://127.0.0.1:8092/default
 *   Replica #0: Index=-1, Host=N/A
 *   [0xd2e790] NEW CONFIG revid: 14, bucket: default, uuid: 44bb7edf04fd3aa86d00a644b2794eea
 */
probe libcouchbase.config.new =
    process("${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcouchbase.so.${LCB_SONAME_FULL}").mark("new_config")
{
    lcb = $arg1
    revid = $arg2
    bucket_name = user_string($arg3)
    bucket_uuid = user_string($arg4)
}
