/** Finalise a marshalled message. * * Depending on the number of values packed, change the type of message, and * write the actual size in the right location of the header, in network byte * order. * * \param mbuf MBuffer where marshalled data is * \return 1 * \see marshal_init, marshal_measurements, marshal_values */ int marshal_finalize(MBuffer* mbuf) { uint8_t* buf = mbuf_message (mbuf); OmlBinMsgType type = marshal_get_msgtype (mbuf); size_t len = mbuf_message_length (mbuf); if (len > UINT32_MAX) { logwarn("Message length %d longer than maximum packet length (%d); " "packet will be truncated\n", len, UINT32_MAX); len = UINT32_MAX; } if (type == OMB_DATA_P && len > UINT16_MAX) { /* * We assumed a short packet, but there is too much data, so we * have to shift the whole buffer down by 2 bytes and convert to a * long packet. */ uint8_t s[2] = {0}; /* Put some padding in the buffer to make sure it has room, and maintains its invariants */ mbuf_write (mbuf, s, sizeof (s)); memmove (&buf[PACKET_HEADER_SIZE+2], &buf[PACKET_HEADER_SIZE], len - PACKET_HEADER_SIZE); len += 2; buf[2] = type = OMB_LDATA_P; } switch (type) { case OMB_DATA_P: len -= PACKET_HEADER_SIZE; // Data length minus header uint16_t nlen16 = htons (len); memcpy (&buf[3], &nlen16, sizeof (nlen16)); break; case OMB_LDATA_P: len -= PACKET_HEADER_SIZE + 2; // Data length minus header uint32_t nlen32 = htonl (len); // pure data length memcpy (&buf[3], &nlen32, sizeof (nlen32)); break; } return 1; }
/** Marshal the array of values into an MBuffer. * * Metadata of the measurement stream should already have been written * with marshal_measurements(). Each element of values is written with * marshal_value(). Finally, the number of elements in the message is * updated in its header, by incrementing the relevant field * (depending on its OmlBinMsgType) by value_count. * * If the returned number is negative, marshalling didn't finish as * the provided buffer was short of the number of bytes returned (when * multiplied by -1); the entire message has been reset (by * marshal_value()), and marshalling should restart with * marshal_init(), after the MBuffer has been adequately resized or * repacked. * * Once all data has been marshalled, marshal_finalize() should be * called to finish preparing the message. * * \param mbuf MBuffer to write marshalled data to * \param values array of OmlValue of length value_count * \param value_count length the values array * \return 1 on success, or -1 otherwise (marshalling should then restart from marshal_init()) * \see marshal_init, marshal_measurements, marshal_value, marshal_finalize, mbuf_repack_message, mbuf_repack_message2, mbuf_resize */ int marshal_values(MBuffer* mbuf, OmlValue* values, int value_count) { OmlValue* val = values; int i; for (i = 0; i < value_count; i++, val++) { if(!marshal_value(mbuf, oml_value_get_type(val), oml_value_get_value(val))) return -1; } uint8_t* buf = mbuf_message (mbuf); OmlBinMsgType type = marshal_get_msgtype (mbuf); switch (type) { case OMB_DATA_P: buf[5] += value_count; break; case OMB_LDATA_P: buf[7] += value_count; break; } return 1; }
/** Function called after all items in a tuple have been sent * \see oml_writer_row_end * * This releases the lock on the BufferedWriter. * * \see BufferedWriter, bw_unlock_buf, marshal_finalize */ static int owb_row_end(OmlWriter* writer, OmlMStream* ms) { (void)ms; OmlBinWriter* self = (OmlBinWriter*)writer; MBuffer* mbuf; if ((mbuf = self->mbuf) == NULL) { return 0; /* previous use of mbuf failed */ } marshal_finalize(self->mbuf); if (marshal_get_msgtype (self->mbuf) == OMB_LDATA_P) { self->msgtype = OMB_LDATA_P; // Generate long packets from now on. } if (0 == ms->index) { /* This is schema0, also push the data into the meta_buf * to be replayed after a disconnection. * * At the moment, the oml_outs_write_f takes header information as a * whole, but does not push more once it has sent the initial block. Its * two last parameters are only used to resend the entirety of the headers * when a disconnection does occur, nothing before. * * We therefore send the extra piece of data the normal way, but also * record it, separately, in the meta_buf * * XXX: This logic should be in higher layer levels, but given the current * implementation, with some of it already spread down into the * OmlOutStream (oml_outs_write_f), this require a much bigger refactoring. * It is also duplicated with the OmlTextWriter (see #1101). */ _bw_push_meta(self->bufferedWriter, mbuf_message(self->mbuf), mbuf_message_length(self->mbuf)); } mbuf_begin_write(mbuf); self->mbuf = NULL; bw_unlock_buf(self->bufferedWriter); return 1; }