@@ -109,6 +109,7 @@ lcb_STATUS mcreq_reserve_key(mc_PIPELINE *pipeline, mc_PACKET *packet, uint8_t h
109109 /* copy collection ID prefix */
110110 if (ncid ) {
111111 memcpy (SPAN_BUFFER (& packet -> kh_span ) + hdrsize , cid , ncid );
112+ packet -> flags |= MCREQ_F_HASCID ;
112113 }
113114 /**
114115 * Copy the key into the packet starting at the extras end
@@ -243,10 +244,89 @@ void mcreq_reenqueue_packet(mc_PIPELINE *pipeline, mc_PACKET *packet)
243244 sllist_insert_sorted (reqs , & packet -> slnode , pkt_tmo_compar );
244245}
245246
247+ static void check_collection_id (mc_PIPELINE * pipeline , mc_PACKET * packet )
248+ {
249+ if ((packet -> flags & MCREQ_F_NOCID ) != 0 ) {
250+ return ;
251+ }
252+
253+ // before adding packet to pipeline lets see if we need add or remove collection id prefix
254+ char * header_and_key = SPAN_BUFFER (& packet -> kh_span );
255+ protocol_binary_request_header * request = (protocol_binary_request_header * )header_and_key ;
256+
257+ uint16_t key_length ;
258+ uint8_t flexible_extras_length = 0 ;
259+
260+ if (request -> request .magic == PROTOCOL_BINARY_AREQ ) {
261+ flexible_extras_length = request -> request .keylen & 0xff ;
262+ key_length = request -> request .keylen >> 8 ;
263+ } else {
264+ key_length = ntohs (request -> request .keylen );
265+ }
266+ if (key_length == 0 ) {
267+ return ;
268+ }
269+
270+ char * key = header_and_key + sizeof (* request ) + request -> request .extlen + flexible_extras_length ;
271+ uint32_t collection_id = 0 ;
272+
273+ uint16_t collection_id_length = 0 ;
274+ if ((packet -> flags & MCREQ_F_HASCID ) != 0 ) {
275+ collection_id_length = (uint16_t )leb128_decode ((const uint8_t * )key , key_length , & collection_id );
276+ }
277+
278+ switch (pipeline -> collections ) {
279+ case MCREQ_COLLECTIONS_SUPPORTED :
280+ // the pipeline had negotiated collections feature with kv engine, so we have to encode collection id
281+ // prefix
282+ if (collection_id_length == 0 ) {
283+ // but collection id prefix was not encoded, we should assume default collection and prepend zero as
284+ // a collection identifier
285+ mcreq_set_cid (pipeline , packet , 0 );
286+ }
287+ break ;
288+
289+ case MCREQ_COLLECTIONS_UNSUPPORTTED :
290+ // the pipeline been told that the kv engine instance does not support collections
291+ if (collection_id_length != 0 ) {
292+ // but the packet has encoded collection id
293+ if (collection_id == 0 ) {
294+ // strip it if it is default collection
295+ request -> request .bodylen = htonl (ntohl (request -> request .bodylen ) - collection_id_length );
296+ uint16_t new_key_length = key_length - collection_id_length ;
297+ if (request -> request .magic == PROTOCOL_BINARY_AREQ ) {
298+ request -> request .keylen = (new_key_length << 8U ) | (flexible_extras_length & 0xffU );
299+ } else {
300+ request -> request .keylen = htons (new_key_length );
301+ }
302+
303+ // shift the key content to the left
304+ for (int i = 0 ; i < new_key_length ; ++ i ) {
305+ key [i ] = key [i + collection_id_length ];
306+ }
307+ } else {
308+ fprintf (
309+ stderr ,
310+ "custom collection id has been dispatched to the node, that does not support collections\n" );
311+ // TODO log error
312+ }
313+ }
314+ break ;
315+
316+ default :
317+ // the pipeline hadn't completed handshake yet, so trust global settings, and let operation be fixed
318+ // when it will be retried in case of misprediction.
319+ fprintf (stderr , "collections has not been negotiated for the pipeline yet\n" );
320+ break ;
321+ }
322+ }
323+
246324void mcreq_enqueue_packet (mc_PIPELINE * pipeline , mc_PACKET * packet )
247325{
248326 nb_SPAN * vspan = & packet -> u_value .single ;
249327 sllist_append (& pipeline -> requests , & packet -> slnode );
328+
329+ check_collection_id (pipeline , packet );
250330 netbuf_enqueue_span (& pipeline -> nbmgr , & packet -> kh_span , packet );
251331 MC_INCR_METRIC (pipeline , bytes_queued , packet -> kh_span .size );
252332
@@ -593,9 +673,10 @@ void mcreq_set_cid(mc_PIPELINE *pipeline, mc_PACKET *packet, uint32_t cid)
593673 netbuf_mblock_release (& pipeline -> nbmgr , & packet -> kh_span );
594674 }
595675 CREATE_STANDALONE_SPAN (& packet -> kh_span , kdata , new_size );
676+ packet -> flags |= MCREQ_F_HASCID ;
596677}
597678
598- uint32_t mcreq_get_cid (lcb_INSTANCE * instance , const mc_PACKET * packet )
679+ uint32_t mcreq_get_cid (lcb_INSTANCE * instance , const mc_PACKET * packet , int * cid_set )
599680{
600681 uint8_t ffext = 0 ;
601682 uint16_t nk = 0 ;
@@ -605,6 +686,10 @@ uint32_t mcreq_get_cid(lcb_INSTANCE *instance, const mc_PACKET *packet)
605686 char * kh = SPAN_BUFFER (& packet -> kh_span );
606687 char * k = NULL ;
607688
689+ if (cid_set != NULL ) {
690+ * cid_set = 0 ;
691+ }
692+
608693 memcpy (& req , kh , sizeof (req ));
609694 if (req .request .magic == PROTOCOL_BINARY_AREQ ) {
610695 ffext = req .request .keylen & 0xff ;
@@ -616,6 +701,9 @@ uint32_t mcreq_get_cid(lcb_INSTANCE *instance, const mc_PACKET *packet)
616701 if ((packet -> flags & MCREQ_F_NOCID ) == 0 && instance && LCBT_SETTING (instance , use_collections )) {
617702 ncid = leb128_decode ((uint8_t * )k , nk , & cid );
618703 if (ncid ) {
704+ if (cid_set != NULL ) {
705+ * cid_set = 1 ;
706+ }
619707 return cid ;
620708 }
621709 }
@@ -702,6 +790,7 @@ int mcreq_pipeline_init(mc_PIPELINE *pipeline)
702790 pipeline -> index = 0 ;
703791 memset (& pipeline -> ctxqueued , 0 , sizeof pipeline -> ctxqueued );
704792 pipeline -> buf_done_callback = NULL ;
793+ pipeline -> collections = MCREQ_COLLECTIONS_UNKNOWN ;
705794
706795 netbuf_default_settings (& settings );
707796
0 commit comments