diff --git a/default_engine.c b/default_engine.c
index 34788a2..43ac61c 100644
--- a/default_engine.c
+++ b/default_engine.c
@@ -84,7 +84,8 @@ ENGINE_ERROR_CODE create_instance(uint64_t interface,
    struct default_engine default_engine = {
       .engine = {
          .interface = {
-            .interface = 1
+            .interface = 1,
+            .features = 0,
          },
          .get_info = default_get_info,
          .initialize = default_initialize,
@@ -102,7 +103,9 @@ ENGINE_ERROR_CODE create_instance(uint64_t interface,
          .item_get_cas = item_get_cas,
          .item_set_cas = item_set_cas,
          .item_get_key = item_get_key,
+	 .item_get_nkey = item_get_nkey,
          .item_get_data = item_get_data,
+	 .item_get_ndata = item_get_ndata,
          .item_get_clsid = item_get_clsid
       },
       .server = *api,
@@ -453,11 +456,21 @@ const char* item_get_key(const item* item)
     return ret;
 }
 
+uint16_t item_get_nkey(const item *item)
+{
+    return item->nkey;
+}
+
 char* item_get_data(const item* item)
 {
     return ((char*)item_get_key(item)) + item->nkey;
 }
 
+uint32_t item_get_ndata(const item *item)
+{
+    return item->nbytes;
+}
+
 uint8_t item_get_clsid(const item* item)
 {
     return 0;
diff --git a/default_engine.h b/default_engine.h
index e6da3f2..669a627 100644
--- a/default_engine.h
+++ b/default_engine.h
@@ -124,6 +124,8 @@ struct default_engine {
 
 char* item_get_data(const item* item);
 const char* item_get_key(const item* item);
+uint16_t item_get_nkey(const item *item);
+uint32_t item_get_ndata(const item *item);
 void item_set_cas(item* item, uint64_t val);
 uint64_t item_get_cas(const item* item);
 uint8_t item_get_clsid(const item* item);
diff --git a/include/memcached/engine.h b/include/memcached/engine.h
index 8f9ca0f..96f20dc 100644
--- a/include/memcached/engine.h
+++ b/include/memcached/engine.h
@@ -86,6 +86,14 @@ extern "C" {
         ON_SWITCH_CONN = 3,     /**< Processing a different connection on this thread. */
     } ENGINE_EVENT_TYPE;
 
+    /**
+     * Flags to inform features of the loaded engine module.
+     */
+    typedef enum {
+        ENGINE_HAS_SECONDARY	= 0x01,	/* It has secondary modules. */
+        ENGINE_HAS_PERSISTENT	= 0x02,	/* Is has persistent storage support. */
+    } ENGINE_FEATURE_SPECS;
+
     #define MAX_ENGINE_EVENT_TYPE 3
 
     /**
@@ -163,6 +171,7 @@ extern "C" {
 #endif
     typedef struct engine_interface {
         uint64_t interface; /**< The version number on the engine structure */
+        uint64_t features;	/**< mask of the ENGINE_FEATURE_FLAGS */
     } ENGINE_HANDLE;
 
     /**
@@ -216,6 +225,19 @@ extern "C" {
         void *(*get_engine_specific)(const void *cookie);
 
         /**
+         * Retrieve socket file descriptor of the session for the given
+         * cookie. It allows engine modules to obtain the properties of
+         * connection, but we don't recommend to update status of the
+         * socket file descriptor retrieved.
+         *
+         * @param cookie The cookie provided by the frontend
+         *
+         * @return the socket file descriptor of the session for the given
+         *         cookie, or -1 on any errors.
+         */
+        int (*get_socket_fd)(const void *cookie);
+
+        /**
          * Get the server's version number.
          *
          * @return the server's version number
@@ -532,11 +554,21 @@ extern "C" {
         const char* (*item_get_key)(const item *item);
 
         /**
+         * Get length of the key from an item
+         */
+        uint16_t (*item_get_nkey)(const item *item);
+
+        /**
          * Get the data from an item.
          */
         char* (*item_get_data)(const item *item);
 
         /**
+         * Get length of the data from an item
+         */
+        uint32_t (*item_get_ndata)(const item *item);
+
+        /**
          * Get an item's class ID.
          */
         uint8_t (*item_get_clsid)(const item* item);
diff --git a/memcached.c b/memcached.c
index 2081aff..d4e7a9f 100644
--- a/memcached.c
+++ b/memcached.c
@@ -999,8 +999,13 @@ static void complete_nread_ascii(conn *c) {
 
     item *it = c->item;
     const void *key = settings.engine.v1->item_get_key(it);
+    const char *data = settings.engine.v1->item_get_data(it);
+#ifdef ENABLE_DTRACE	/* to keep compiler quiet */
+    uint16_t nkey = settings.engine.v1->item_get_nkey(it);
+#endif
+    uint32_t nbytes = settings.engine.v1->item_get_ndata(it);
 
-    if (strncmp(settings.engine.v1->item_get_data(it) + it->nbytes - 2, "\r\n", 2) != 0) {
+    if (strncmp(data + nbytes - 2, "\r\n", 2) != 0) {
         out_string(c, "CLIENT_ERROR bad data chunk");
     } else {
         ENGINE_ERROR_CODE ret = settings.engine.v1->store(settings.engine.v0, c,
@@ -1009,27 +1014,27 @@ static void complete_nread_ascii(conn *c) {
 #ifdef ENABLE_DTRACE
         switch (c->store_op) {
         case OPERATION_ADD:
-            MEMCACHED_COMMAND_ADD(c->sfd, key, it->nkey,
-                                  (ret == ENGINE_SUCCESS) ? it->nbytes : -1, c->cas);
+            MEMCACHED_COMMAND_ADD(c->sfd, key, nkey,
+                                  (ret == ENGINE_SUCCESS) ? nbytes : -1, c->cas);
             break;
         case OPERATION_REPLACE:
-            MEMCACHED_COMMAND_REPLACE(c->sfd, key, it->nkey,
-                                      (ret == ENGINE_SUCCESS) ? it->nbytes : -1, c->cas);
+            MEMCACHED_COMMAND_REPLACE(c->sfd, key, nkey,
+                                      (ret == ENGINE_SUCCESS) ? nbytes : -1, c->cas);
             break;
         case OPERATION_APPEND:
-            MEMCACHED_COMMAND_APPEND(c->sfd, key, it->nkey,
-                                     (ret == ENGINE_SUCCESS) ? it->nbytes : -1, c->cas);
+            MEMCACHED_COMMAND_APPEND(c->sfd, key, nkey,
+                                     (ret == ENGINE_SUCCESS) ? nbytes : -1, c->cas);
             break;
         case OPERATION_PREPEND:
-            MEMCACHED_COMMAND_PREPEND(c->sfd, key, it->nkey,
-                                      (ret == ENGINE_SUCCESS) ? it->nbytes : -1, c->cas);
+            MEMCACHED_COMMAND_PREPEND(c->sfd, key, nkey,
+                                      (ret == ENGINE_SUCCESS) ? nbytes : -1, c->cas);
             break;
         case OPERATION_SET:
-            MEMCACHED_COMMAND_SET(c->sfd, key, it->nkey,
-                                  (ret == ENGINE_SUCCESS) ? it->nbytes : -1, c->cas);
+            MEMCACHED_COMMAND_SET(c->sfd, key, nkey,
+                                  (ret == ENGINE_SUCCESS) ? nbytes : -1, c->cas);
             break;
         case OPERATION_CAS:
-            MEMCACHED_COMMAND_CAS(c->sfd, key, it->nkey, it->nbytes, c->cas);
+            MEMCACHED_COMMAND_CAS(c->sfd, key, nkey, nbytes, c->cas);
             break;
         }
 #endif
@@ -1369,11 +1374,17 @@ static void complete_update_bin(conn *c) {
     assert(c != NULL);
 
     item *it = c->item;
+#ifdef ENABLE_DTRACE
+    const char *key = settings.engine.v1->item_get_key(it);
+    uint16_t nkey = settings.engine.v1->item_get_nkey(it);
+#endif	/* to keep compiler quiet */
+    char *data = settings.engine.v1->item_get_data(it);
+    uint32_t nbytes = settings.engine.v1->item_get_ndata(it);
 
     /* We don't actually receive the trailing two characters in the bin
      * protocol, so we're going to just set them here */
-    *(settings.engine.v1->item_get_data(it) + it->nbytes - 2) = '\r';
-    *(settings.engine.v1->item_get_data(it) + it->nbytes - 1) = '\n';
+    data[nbytes - 2] = '\r';
+    data[nbytes - 1] = '\n';
 
     ENGINE_ERROR_CODE ret = c->aiostat;
     c->aiostat = ENGINE_SUCCESS;
@@ -1385,24 +1396,24 @@ static void complete_update_bin(conn *c) {
 #ifdef ENABLE_DTRACE
     switch (c->cmd) {
     case OPERATION_ADD:
-        MEMCACHED_COMMAND_ADD(c->sfd, settings.engine.v1->item_get_key(it), it->nkey,
-                              (ret == ENGINE_SUCCESS) ? it->nbytes : -1, c->cas);
+        MEMCACHED_COMMAND_ADD(c->sfd, key, nkey,
+                              (ret == ENGINE_SUCCESS) ? nbytes : -1, c->cas);
         break;
     case OPERATION_REPLACE:
-        MEMCACHED_COMMAND_REPLACE(c->sfd, settings.engine.v1->item_get_key(it), it->nkey,
-                                  (ret == ENGINE_SUCCESS) ? it->nbytes : -1, c->cas);
+        MEMCACHED_COMMAND_REPLACE(c->sfd, key, nkey,
+                                  (ret == ENGINE_SUCCESS) ? nbytes : -1, c->cas);
         break;
     case OPERATION_APPEND:
-        MEMCACHED_COMMAND_APPEND(c->sfd, settings.engine.v1->item_get_key(it), it->nkey,
-                                 (ret == ENGINE_SUCCESS) ? it->nbytes : -1, c->cas);
+        MEMCACHED_COMMAND_APPEND(c->sfd, key, nkey,
+                                 (ret == ENGINE_SUCCESS) ? nbytes : -1, c->cas);
         break;
     case OPERATION_PREPEND:
-        MEMCACHED_COMMAND_PREPEND(c->sfd, settings.engine.v1->item_get_key(it), it->nkey,
-                                 (ret == ENGINE_SUCCESS) ? it->nbytes : -1, c->cas);
+        MEMCACHED_COMMAND_PREPEND(c->sfd, key, nkey,
+                                 (ret == ENGINE_SUCCESS) ? nbytes : -1, c->cas);
         break;
     case OPERATION_SET:
-        MEMCACHED_COMMAND_SET(c->sfd, settings.engine.v1->item_get_key(it), it->nkey,
-                              (ret == ENGINE_SUCCESS) ? it->nbytes : -1, c->cas);
+        MEMCACHED_COMMAND_SET(c->sfd, key, nkey,
+                              (ret == ENGINE_SUCCESS) ? nbytes : -1, c->cas);
         break;
     }
 #endif
@@ -1472,7 +1483,7 @@ static void process_bin_get(conn *c) {
     case ENGINE_SUCCESS:
         /* the length has two unnecessary bytes ("\r\n") */
         keylen = 0;
-        bodylen = sizeof(rsp->message.body) + (it->nbytes - 2);
+        bodylen = sizeof(rsp->message.body) + settings.engine.v1->item_get_ndata(it) - 2;
 
         STATS_HIT(c, get, key, nkey);
 
@@ -1492,8 +1503,9 @@ static void process_bin_get(conn *c) {
         }
 
         /* Add the data minus the CRLF */
-        add_iov(c, settings.engine.v1->item_get_data(it), it->nbytes - 2);
-        conn_set_state(c, conn_mwrite);
+        add_iov(c, settings.engine.v1->item_get_data(it),
+                   settings.engine.v1->item_get_ndata(it) - 2);
+         conn_set_state(c, conn_mwrite);
         /* Remember this command so we can garbage collect it later */
         c->item = it;
         break;
@@ -2473,8 +2485,6 @@ static void process_bin_flush(conn *c) {
 }
 
 static void process_bin_delete(conn *c) {
-    item *it;
-
     protocol_binary_request_delete* req = binary_get_request(c);
 
     char* key = binary_get_key(c);
@@ -3020,7 +3030,12 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
             }
 
             if (it) {
-                assert(memcmp(settings.engine.v1->item_get_data(it) + it->nbytes - 2, "\r\n", 2) == 0);
+                const char *key = settings.engine.v1->item_get_key(it);
+                char *data = settings.engine.v1->item_get_data(it);
+                uint16_t nkey = settings.engine.v1->item_get_nkey(it);
+                uint32_t nbytes = settings.engine.v1->item_get_ndata(it);
+
+                assert(memcmp(data + nbytes - 2, "\r\n", 2) == 0);
 
                 if (i >= c->isize) {
                     item **new_list = realloc(c->ilist, sizeof(item *) * c->isize * 2);
@@ -3043,7 +3058,7 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
                 int suffix_len = snprintf(suffix, SUFFIX_SIZE,
                                           " %u %u\r\n",
                                           it->flags,
-                                          it->nbytes - 2);
+                                          nbytes - 2);
 
                 /*
                  * Construct the response. Each hit adds three elements to the
@@ -3055,8 +3070,8 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
 
                 if (return_cas)
                 {
-                  MEMCACHED_COMMAND_GET(c->sfd, settings.engine.v1->item_get_key(it), it->nkey,
-                                        it->nbytes, settings.engine.v1->item_get_cas(it));
+                  MEMCACHED_COMMAND_GET(c->sfd, key, nkey, nbytes,
+                                        settings.engine.v1->item_get_cas(it));
 
                   char *cas = get_suffix_buffer(c);
                   if (cas == NULL) {
@@ -3068,10 +3083,10 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
                                             " %"PRIu64"\r\n",
                                             settings.engine.v1->item_get_cas(it));
                   if (add_iov(c, "VALUE ", 6) != 0 ||
-                      add_iov(c, settings.engine.v1->item_get_key(it), it->nkey) != 0 ||
+                      add_iov(c, key, nkey) != 0 ||
                       add_iov(c, suffix, suffix_len - 2) != 0 ||
                       add_iov(c, cas, cas_len) != 0 ||
-                      add_iov(c, settings.engine.v1->item_get_data(it), it->nbytes) != 0)
+                      add_iov(c, data, nbytes) != 0)
                       {
                           settings.engine.v1->release(settings.engine.v0, c, it);
                           break;
@@ -3079,12 +3094,12 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
                 }
                 else
                 {
-                  MEMCACHED_COMMAND_GET(c->sfd, settings.engine.v1->item_get_key(it), it->nkey,
-                                        it->nbytes, settings.engine.v1->item_get_cas(it));
+                  MEMCACHED_COMMAND_GET(c->sfd, key, nkey, nbytes,
+                                        settings.engine.v1->item_get_cas(it));
                   if (add_iov(c, "VALUE ", 6) != 0 ||
-                      add_iov(c, settings.engine.v1->item_get_key(it), it->nkey) != 0 ||
+                      add_iov(c, key, nkey) != 0 ||
                       add_iov(c, suffix, suffix_len) != 0 ||
-                      add_iov(c, settings.engine.v1->item_get_data(it), it->nbytes) != 0)
+                      add_iov(c, data, nbytes) != 0)
                       {
                           settings.engine.v1->release(settings.engine.v0, c, it);
                           break;
@@ -3094,8 +3109,7 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
 
                 if (settings.verbose > 1) {
                     settings.extensions.logger->log(EXTENSION_LOG_DEBUG, c,
-                             ">%d sending key %s\n", c->sfd,
-                             settings.engine.v1->item_get_key(it));
+                             ">%d sending key %s\n", c->sfd, key);
                 }
 
                 /* item_get() has incremented it->refcount for us */
@@ -3214,7 +3228,7 @@ static void process_update_command(conn *c, token_t *tokens, const size_t ntoken
 
         c->item = it;
         c->ritem = settings.engine.v1->item_get_data(it);
-        c->rlbytes = it->nbytes;
+        c->rlbytes = settings.engine.v1->item_get_ndata(it);
         c->store_op = store_op;
         conn_set_state(c, conn_nread);
         break;
@@ -3311,7 +3325,6 @@ static void process_arithmetic_command(conn *c, token_t *tokens, const size_t nt
 static void process_delete_command(conn *c, token_t *tokens, const size_t ntokens) {
     char *key;
     size_t nkey;
-    item *it;
 
     assert(c != NULL);
 
@@ -4760,6 +4773,11 @@ static void *get_engine_specific(const void *cookie) {
     return c->engine_storage;
 }
 
+static int get_socket_fd(const void *cookie) {
+    conn *c = (conn *)cookie;
+    return c->sfd;
+}
+
 static void *new_independent_stats(void) {
     int ii;
     struct independent_stats *independent_stats = calloc(sizeof(independent_stats) + sizeof(struct thread_stats) * settings.num_threads, 1);
@@ -4925,6 +4943,7 @@ static void *get_server_api(server_api_t interface)
         .get_auth_data = get_auth_data,
         .store_engine_specific = store_engine_specific,
         .get_engine_specific = get_engine_specific,
+        .get_socket_fd = get_socket_fd,
         .server_version = get_server_version,
         .hash = hash,
         .realtime = realtime,
