Пример #1
0
/**
 * Process a slave replication registration message.
 *
 * We store the various bits of information the slave gives us and generate
 * a reply message.
 *
 * @param	router		The router instance
 * @param	slave		The slave server
 * @param	queue		The BINLOG_DUMP packet
 * @return			Non-zero if data was sent
 */
static int
blr_slave_register(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue)
{
GWBUF	*resp;
uint8_t	*ptr;
int	len, slen;

	ptr = GWBUF_DATA(queue);
	len = extract_field(ptr, 24);
	ptr += 4;		// Skip length and sequence number
	if (*ptr++ != COM_REGISTER_SLAVE)
		return 0;
	slave->serverid = extract_field(ptr, 32);
	ptr += 4;
	slen = *ptr++;
	if (slen != 0)
	{
		slave->hostname = strndup((char *)ptr, slen);
		ptr += slen;
	}
	else
		slave->hostname = NULL;
	slen = *ptr++;
	if (slen != 0)
	{
		ptr += slen;
		slave->user = strndup((char *)ptr, slen);
	}
	else
		slave->user = NULL;
	slen = *ptr++;
	if (slen != 0)
	{
		slave->passwd = strndup((char *)ptr, slen);
		ptr += slen;
	}
	else
		slave->passwd = NULL;
	slave->port = extract_field(ptr, 16);
	ptr += 2;
	slave->rank = extract_field(ptr, 32);

	/*
	 * Now construct a response
	 */
	if ((resp = gwbuf_alloc(11)) == NULL)
		return 0;
	ptr = GWBUF_DATA(resp);
	encode_value(ptr, 7, 24);	// Payload length
	ptr += 3;
	*ptr++ = 1;			// Sequence number
	encode_value(ptr, 0, 24);
	ptr += 3;
	encode_value(ptr, slave->serverid, 32);
	slave->state = BLRS_REGISTERED;
	return slave->dcb->func.write(slave->dcb, resp);
}
Пример #2
0
unsigned int NetGameNetworkData::encode_value(unsigned char *d, const NetGameEventValue &value)
{
	switch (value.get_type())
	{
	case NetGameEventValue::null:
		*d = 1;
		return 1;
	case NetGameEventValue::uinteger:
		*d = 2;
		*reinterpret_cast<unsigned int*>(d + 1) = value.to_uinteger();
		return 5;
	case NetGameEventValue::integer:
		*d = 3;
		*reinterpret_cast<int*>(d + 1) = value.to_integer();
		return 5;
	case NetGameEventValue::number:
		*d = 4;
		*reinterpret_cast<float*>(d + 1) = value.to_number();
		return 5;
	case NetGameEventValue::boolean:
		*d = value.to_boolean() ? 6 : 5;
		return 1;
	case NetGameEventValue::string:
		{
			std::string s = value.to_string();
			*d = 7;
			*reinterpret_cast<unsigned short*>(d + 1) = s.length();
			memcpy(d + 3, s.data(), s.length());
			return 3 + s.length();
		}
	case NetGameEventValue::complex:
		{
			d[0] = 8;
			unsigned l = 1;
			for (unsigned int i = 0; i < value.get_member_count(); i++)
				l += encode_value(d + l, value.get_member(i));
			d[l] = 0;
			l++;
			return l;
		}
	case NetGameEventValue::ucharacter:
		*d = 9;
		*reinterpret_cast<unsigned char*>(d + 1) = value.to_ucharacter();
		return 2;
	case NetGameEventValue::character:
		*d = 10;
		*reinterpret_cast<char*>(d + 1) = value.to_character();
		return 2;
	case NetGameEventValue::binary:
		{
			DataBuffer s = value.to_binary();
			*d = 11;
			*reinterpret_cast<unsigned short*>(d + 1) = s.get_size();
			memcpy(d + 3, s.get_data(), s.get_size());
			return 3 + s.get_size();
		}
	default:
		throw Exception("Unknown game event value type");
	}
}
Пример #3
0
DataBuffer NetGameNetworkData::encode_event(const NetGameEvent &e)
{
	unsigned int length = 3 + e.get_name().length();
	for (unsigned int i = 0; i < e.get_argument_count(); i++)
		length += get_encoded_length(e.get_argument(i));

	DataBuffer data(length + 2);

	*data.get_data<unsigned short>() = length;

	unsigned char *d = data.get_data<unsigned char>() + 2;

	// Write name (2 + name length)
	unsigned int name_length = e.get_name().length();
	*reinterpret_cast<unsigned short*>(d) = name_length;
	d += 2;
	memcpy(d, e.get_name().data(), name_length);
	d += name_length;

	for (unsigned int i = 0; i < e.get_argument_count(); i++)
		d += encode_value(d, e.get_argument(i));

	// Write end marker
	*d = 0;

	return data;
}
Пример #4
0
/**
 * Send a response to a "SELECT UNIX_TIMESTAMP()" request. This differs from the other
 * requests since we do not save a copy of the original interaction with the master
 * and simply replay it. We want to always send the current time. We have stored a typcial
 * response, which gives us the schema information normally returned. This is sent to the
 * client and then we add a dynamic part that will insert the current timestamp data.
 * Finally we send a preprepaed EOF packet to end the response stream.
 *
 * @param	router		The binlog router instance
 * @param	slave		The slave server to which we are sending the response
 * @return	Non-zero if data was sent
 */
static int
blr_slave_send_timestamp(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
{
GWBUF	*pkt;
char	timestamp[20];
uint8_t *ptr;
int	len, ts_len;

	sprintf(timestamp, "%ld", time(0));
	ts_len = strlen(timestamp);
	len = sizeof(timestamp_def) + sizeof(timestamp_eof) + 5 + ts_len;
	if ((pkt = gwbuf_alloc(len)) == NULL)
		return 0;
	ptr = GWBUF_DATA(pkt);
	memcpy(ptr, timestamp_def, sizeof(timestamp_def));	// Fixed preamble
	ptr += sizeof(timestamp_def);
	encode_value(ptr, ts_len + 1, 24);			// Add length of data packet
	ptr += 3;
	*ptr++ = 0x04;						// Sequence number in response
	*ptr++ = ts_len;					// Length of result string
	strncpy((char *)ptr, timestamp, ts_len);		// Result string
	ptr += ts_len;
	memcpy(ptr, timestamp_eof, sizeof(timestamp_eof));	// EOF packet to terminate result
	return slave->dcb->func.write(slave->dcb, pkt);
}
Пример #5
0
string t_header::encode_env(void) const {
	string s("SIP_");
	s += toupper(replace_char(header_name, '-', '_'));
	s += '=';
	s += encode_value();
	
	return s;
}
Пример #6
0
/**
 * Send a "fake" format description event to the newly connected slave
 *
 * @param router	The router instance
 * @param slave		The slave to send the event to
 */
static void
blr_slave_send_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
{
BLFILE		*file;
REP_HEADER	hdr;
GWBUF		*record, *head;
uint8_t		*ptr;
uint32_t	chksum;

	if ((file = blr_open_binlog(router, slave->binlogfile)) == NULL)
		return;
	if ((record = blr_read_binlog(router, file, 4, &hdr)) == NULL)
	{
		blr_close_binlog(router, file);
		return;
	}
	blr_close_binlog(router, file);
	head = gwbuf_alloc(5);
	ptr = GWBUF_DATA(head);
	encode_value(ptr, hdr.event_size + 1, 24); // Payload length
	ptr += 3;
	*ptr++ = slave->seqno++;
	*ptr++ = 0;		// OK
	head = gwbuf_append(head, record);
	ptr = GWBUF_DATA(record);
	encode_value(ptr, time(0), 32);		// Overwrite timestamp
	ptr += 13;
	encode_value(ptr, 0, 32);		// Set next position to 0
	/*
	 * Since we have changed the timestamp we must recalculate the CRC
	 *
	 * Position ptr to the start of the event header,
	 * calculate a new checksum
	 * and write it into the header
	 */
	ptr = GWBUF_DATA(record) + hdr.event_size - 4;
	chksum = crc32(0L, NULL, 0);
	chksum = crc32(chksum, GWBUF_DATA(record), hdr.event_size - 4);
	encode_value(ptr, chksum, 32);
	slave->dcb->func.write(slave->dcb, head);
}
Пример #7
0
/**
 * Populate a header structure for a replication message from a GWBUF structure.
 *
 * @param pkt	The incoming packet in a GWBUF chain
 * @param hdr	The packet header to populate
 * @return 	A pointer to the first byte following the event header
 */
uint8_t *
blr_build_header(GWBUF	*pkt, REP_HEADER *hdr)
{
uint8_t	*ptr;

	ptr = GWBUF_DATA(pkt);

	encode_value(ptr, hdr->payload_len, 24);
	ptr += 3;
	*ptr++ = hdr->seqno;
	*ptr++ = hdr->ok;
	encode_value(ptr, hdr->timestamp, 32);
	ptr += 4;
	*ptr++ = hdr->event_type;
	encode_value(ptr, hdr->serverid, 32);
	ptr += 4;
	encode_value(ptr, hdr->event_size, 32);
	ptr += 4;
	encode_value(ptr, hdr->next_pos, 32);
	ptr += 4;
	encode_value(ptr, hdr->flags, 16);
	ptr += 2;

	return ptr;
}
Пример #8
0
/**
 * Send the column definition packet in a response packet sequence.
 *
 * @param router	The router
 * @param slave		The slave connection
 * @param name		Name of the column
 * @param type		Column type
 * @param len		Column length
 * @param seqno		Packet sequence number
 * @return		Non-zero on success
 */
static int
blr_slave_send_columndef(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, char *name, int type, int len, uint8_t seqno)
{
GWBUF	*pkt;
uint8_t *ptr;

	if ((pkt = gwbuf_alloc(26 + strlen(name))) == NULL)
		return 0;
	ptr = GWBUF_DATA(pkt);
	encode_value(ptr, 22 + strlen(name), 24);	// Add length of data packet
	ptr += 3;
	*ptr++ = seqno;					// Sequence number in response
	*ptr++ = 3;					// Catalog is always def
	*ptr++ = 'd';
	*ptr++ = 'e';
	*ptr++ = 'f';
	*ptr++ = 0;					// Schema name length
	*ptr++ = 0;					// virtal table name length
	*ptr++ = 0;					// Table name length
	*ptr++ = strlen(name);				// Column name length;
	while (*name)
		*ptr++ = *name++;			// Copy the column name
	*ptr++ = 0;					// Orginal column name
	*ptr++ = 0x0c;					// Length of next fields always 12
	*ptr++ = 0x3f;					// Character set
	*ptr++ = 0;
	encode_value(ptr, len, 32);			// Add length of column
	ptr += 4;
	*ptr++ = type;
	*ptr++ = 0x81;					// Two bytes of flags
	if (type == 0xfd)
		*ptr++ = 0x1f;
	else
		*ptr++ = 0x00;
	*ptr++= 0;
	*ptr++= 0;
	*ptr++= 0;
	return slave->dcb->func.write(slave->dcb, pkt);
}
Пример #9
0
string t_header::encode(void) const {
	string s;

	if (!populated) return s;

	s = (t_parser::compact_headers && !compact_name.empty() ? 
			compact_name : header_name);
	s += ": ";
	s += encode_value();
	s += CRLF;
	
	return s;
}
Пример #10
0
/**
 * Send the field count packet in a response packet sequence.
 *
 * @param router	The router
 * @param slave		The slave connection
 * @param count		Number of columns in the result set
 * @return		Non-zero on success
 */
static int
blr_slave_send_fieldcount(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, int count)
{
GWBUF	*pkt;
uint8_t *ptr;

	if ((pkt = gwbuf_alloc(5)) == NULL)
		return 0;
	ptr = GWBUF_DATA(pkt);
	encode_value(ptr, 1, 24);			// Add length of data packet
	ptr += 3;
	*ptr++ = 0x01;					// Sequence number in response
	*ptr++ = count;					// Length of result string
	return slave->dcb->func.write(slave->dcb, pkt);
}
Пример #11
0
    static void
cb_params_store_init_item(struct params_st *params, lcb_size_t idx,
        VALUE key_obj, VALUE value_obj, lcb_uint32_t flags, lcb_cas_t cas,
        lcb_time_t exptime)
{
    key_obj = unify_key(params->bucket, key_obj, 1);
    value_obj = encode_value(value_obj, params->cmd.store.flags);
    if (value_obj == Qundef) {
        rb_raise(eValueFormatError, "unable to convert value for key '%s'", RSTRING_PTR(key_obj));
    }
    params->cmd.store.items[idx].v.v0.datatype = params->cmd.store.datatype;
    params->cmd.store.items[idx].v.v0.operation = params->cmd.store.operation;
    params->cmd.store.items[idx].v.v0.key = RSTRING_PTR(key_obj);
    params->cmd.store.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
    params->cmd.store.items[idx].v.v0.bytes = RSTRING_PTR(value_obj);
    params->cmd.store.items[idx].v.v0.nbytes = RSTRING_LEN(value_obj);
    params->cmd.store.items[idx].v.v0.flags = flags;
    params->cmd.store.items[idx].v.v0.cas = cas;
    params->cmd.store.items[idx].v.v0.exptime = exptime;
    params->npayload += RSTRING_LEN(key_obj) + RSTRING_LEN(value_obj) + sizeof(flags) + sizeof(exptime);
}
Пример #12
0
/**
 * Construct an error response
 *
 * @param router	The router instance
 * @param slave		The slave server instance
 * @param msg		The error message to send
 */
static void
blr_slave_send_error(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, char  *msg)
{
GWBUF		*pkt;
unsigned char   *data;
int             len;

        if ((pkt = gwbuf_alloc(strlen(msg) + 13)) == NULL)
                return;
        data = GWBUF_DATA(pkt);
        len = strlen(msg) + 1;
        encode_value(&data[0], len, 24);	// Payload length
        data[3] = 0;				// Sequence id
						// Payload
        data[4] = 0xff;				// Error indicator
	data[5] = 0;				// Error Code
	data[6] = 0;				// Error Code
	strncpy((char *)&data[7], "#00000", 6);
        memcpy(&data[13], msg, strlen(msg));	// Error Message
	slave->dcb->func.write(slave->dcb, pkt);
}
Пример #13
0
// Return the data for all the names[], start .. end etc.
// as get_values() is supposed to return them.
//
// Returns raw values if interpol <= 0.0.
// Returns 0 on error.
xmlrpc_value *get_sheet_data(xmlrpc_env *env,
                             int key,
                             const stdVector<stdString> names,
                             const epicsTime &start, const epicsTime &end,
                             long count,
                             ReaderFactory::How how, double delta)
{
    try
    {
#ifdef LOGFILE
        stdString txt;
        LOG_MSG("get_sheet_data\n");
        LOG_MSG("Start : %s\n", epicsTimeTxt(start, txt));
        LOG_MSG("End   : %s\n", epicsTimeTxt(end, txt));
        LOG_MSG("Method: %s\n", ReaderFactory::toString(how, delta));
 #endif
        AutoPtr<Index> index(open_index(env, key));
        if (env->fault_occurred)
            return 0;

        AutoPtr<SpreadsheetReader> sheet(new SpreadsheetReader(*index, how, delta));
    
        AutoXmlRpcValue results(xmlrpc_build_value(env, "()"));
        if (env->fault_occurred)
            return 0;    

        long name_count = names.size();
        AutoArrayPtr<AutoXmlRpcValue> meta     (new AutoXmlRpcValue[name_count]);
        AutoArrayPtr<AutoXmlRpcValue> values   (new AutoXmlRpcValue[name_count]);
        AutoArrayPtr<xmlrpc_int32>    xml_type (new xmlrpc_int32[name_count]);
        AutoArrayPtr<xmlrpc_int32>    xml_count(new xmlrpc_int32[name_count]);
        AutoArrayPtr<size_t>          ch_vals  (new size_t[name_count]);
        bool ok = sheet->find(names, &start);
        long i;
        // Per-channel meta-info.
        for (i=0; i<name_count; ++i)
        {
#ifdef LOGFILE
            LOG_MSG("Handling '%s'\n", names[i].c_str());
#endif
            ch_vals[i] = 0;
            values[i] = xmlrpc_build_value(env, "()");            
            if (env->fault_occurred)
                return 0;
            if (sheet->found(i))
            {   // Fix meta/type/count based on first value
                meta[i] = encode_ctrl_info(env, &sheet->getInfo(i));
                dbr_type_to_xml_type(sheet->getType(i), sheet->getCount(i),
                                     xml_type[i], xml_count[i]);
#if 0
                LOG_MSG("Ch %lu: type, count = %d, %d\n", i, (int)xml_type[i], (int)xml_count[i]);
#endif
            }
            else
            {   // Channel exists, but has no data
                meta[i] = encode_ctrl_info(env, 0);
                xml_type[i] = XML_ENUM;
                xml_count[i] = 1;
            }
        }
        // Collect values
        long num_vals = 0;
        while (ok && num_vals < count && sheet->getTime() < end)
        {
            for (i=0; i<name_count; ++i)
            {
                if (sheet->get(i))
                {
                    ++ch_vals[i];
                    encode_value(env,
                                 sheet->getType(i), sheet->getCount(i),
                                 sheet->getTime(), sheet->get(i),
                                 xml_type[i], xml_count[i], values[i]);
                }
                else
                {   // Encode as no value, but one of them ;-)
                    // to avoid confusion w/ viewers that like to see some data in any case.
                    encode_value(env, 0, 1, sheet->getTime(), 0,
                                 xml_type[i], xml_count[i], values[i]);
                }
                
            }
            ++num_vals;
            ok = sheet->next();
        }
        // Assemble result = { name, meta, type, count, values }
        for (i=0; i<name_count; ++i)
        {
            AutoXmlRpcValue result(
                xmlrpc_build_value(env, "{s:s,s:V,s:i,s:i,s:V}",
                                   "name",   names[i].c_str(),
                                   "meta",   meta[i].get(),
                                   "type",   xml_type[i],
                                   "count",  xml_count[i],
                                   "values", values[i].get()));    
            // Add to result array
            xmlrpc_array_append_item(env, results, result);
#ifdef LOGFILE
            LOG_MSG("Ch %lu: %zu values\n", i, ch_vals[i]);
#endif
        }
#ifdef LOGFILE
        LOG_MSG("%ld values total\n", num_vals);
#endif
        return results.release();
    }
    catch (GenericException &e)
    {
#ifdef LOGFILE
        LOG_MSG("Error:\n%s\n", e.what());
#endif
        xmlrpc_env_set_fault_formatted(env, ARCH_DAT_DATA_ERROR,
                                       "%s", e.what());
    }
    return 0;
}
Пример #14
0
// Return the data for all the names[], start .. end etc.
// as get_values() is supposed to return them.
// Returns 0 on error.
xmlrpc_value *get_channel_data(xmlrpc_env *env,
                               int key,
                               const stdVector<stdString> names,
                               const epicsTime &start, const epicsTime &end,
                               long count,
                               ReaderFactory::How how, double delta)
{
    AutoXmlRpcValue results;
    try
    {
#ifdef LOGFILE
        stdString txt;
        LOG_MSG("get_channel_data\n");
        LOG_MSG("Method: %s\n", ReaderFactory::toString(how, delta));
        LOG_MSG("Start:  %s\n", epicsTimeTxt(start, txt));
        LOG_MSG("End  :  %s\n", epicsTimeTxt(end, txt));
#endif
        AutoPtr<Index> index(open_index(env, key));
        if (env->fault_occurred)
            return 0;
        AutoPtr<DataReader> reader(ReaderFactory::create(*index, how, delta));
        results = xmlrpc_build_value(env, "()");
        if (env->fault_occurred)
            return 0;
        long i, name_count = names.size();
        for (i=0; i<name_count; ++i)
        {
#ifdef LOGFILE
            LOG_MSG("Handling '%s'\n", names[i].c_str());
#endif
            long num_vals = 0;            
            AutoXmlRpcValue values(xmlrpc_build_value(env, "()"));
            if (env->fault_occurred)
                return 0;
            const RawValue::Data *data = reader->find(names[i], &start);
            AutoXmlRpcValue meta;
            xmlrpc_int32 xml_type, xml_count;
            if (data == 0)
            {   // No exception from file error etc., just no data.
                meta = encode_ctrl_info(env, 0);
                xml_type = XML_ENUM;
                xml_count = 1;
            }
            else
            {
                // Fix meta/type/count based on first value
                meta = encode_ctrl_info(env, &reader->getInfo());
                dbr_type_to_xml_type(reader->getType(), reader->getCount(),
                                     xml_type, xml_count);
                while (num_vals < count
                       && data
                       && RawValue::getTime(data) < end)
                {
                    encode_value(env, reader->getType(), reader->getCount(),
                                 RawValue::getTime(data), data,
                                 xml_type, xml_count, values);
                    ++num_vals;
                    data = reader->next();
                }
            }
            // Assemble result = { name, meta, type, count, values }
            AutoXmlRpcValue result(xmlrpc_build_value(
                                       env, "{s:s,s:V,s:i,s:i,s:V}",
                                       "name",   names[i].c_str(),
                                       "meta",   (xmlrpc_value *)meta,
                                       "type",   xml_type,
                                       "count",  xml_count,
                                       "values", (xmlrpc_value *)values));
            // Add to result array
            xmlrpc_array_append_item(env, results, result);
#ifdef LOGFILE
            LOG_MSG("%ld values\n", num_vals);
#endif
        } // for ( .. name .. )
    }
    catch (GenericException &e)
    {
#ifdef LOGFILE
        LOG_MSG("Error:\n%s\n", e.what());
#endif
        xmlrpc_env_set_fault_formatted(env, ARCH_DAT_DATA_ERROR,
                                       "%s", e.what());
        return 0;
    }
    return results.release();
}
Пример #15
0
static int load_registration_id(PROV_AUTH_INFO* handle)
{
    int result;
    if (handle->sec_type == PROV_AUTH_TYPE_TPM)
    {
        SHA256Context sha_ctx;
        uint8_t msg_digest[SHA256HashSize];
        unsigned char* endorsement_key;
        size_t ek_len;

        if (handle->hsm_client_get_endorsement_key(handle->hsm_client_handle, &endorsement_key, &ek_len) != 0)
        {
            LogError("Failed getting device reg id");
            result = MU_FAILURE;
        }
        else
        {
            if (SHA256Reset(&sha_ctx) != 0)
            {
                LogError("Failed sha256 reset");
                result = MU_FAILURE;
            }
            else if (SHA256Input(&sha_ctx, endorsement_key, (unsigned int)ek_len) != 0)
            {
                LogError("Failed SHA256Input");
                result = MU_FAILURE;
            }
            else if (SHA256Result(&sha_ctx, msg_digest) != 0)
            {
                LogError("Failed SHA256Result");
                result = MU_FAILURE;
            }
            else
            {
                handle->registration_id = encode_value(msg_digest, SHA256HashSize);
                if (handle->registration_id == NULL)
                {
                    LogError("Failed allocating registration Id");
                    result = MU_FAILURE;
                }
                else
                {
                    result = 0;
                }
            }
            free(endorsement_key);
        }
    }
    else
    {
        handle->registration_id = handle->hsm_client_get_common_name(handle->hsm_client_handle);
        if (handle->registration_id == NULL)
        {
            LogError("Failed getting common name from certificate");
            result = MU_FAILURE;
        }
        else
        {
            result = 0;
        }
    }
    return result;
}
Пример #16
0
/**
 *  Generate an internal rotate event that we can use to cause the slave to move beyond
 * a binlog file that is misisng the rotate eent at the end.
 *
 * @param router	The router instance
 * @param slave		The slave to rotate
 * @return  Non-zero if the rotate took place
 */
static int
blr_slave_fake_rotate(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
{
char		*sptr;
int		filenum;
GWBUF		*resp;
uint8_t		*ptr;
int		len, binlognamelen;
REP_HEADER	hdr;
uint32_t	chksum;

	if ((sptr = strrchr(slave->binlogfile, '.')) == NULL)
		return 0;
	blr_close_binlog(router, slave->file);
	filenum = atoi(sptr + 1);
	sprintf(slave->binlogfile, BINLOG_NAMEFMT, router->fileroot, filenum + 1);
	slave->binlog_pos = 4;
	if ((slave->file = blr_open_binlog(router, slave->binlogfile)) == NULL)
		return 0;

	binlognamelen = strlen(slave->binlogfile);

	if (slave->nocrc)
		len = 19 + 8 + binlognamelen;
	else
		len = 19 + 8 + 4 + binlognamelen;

	// Build a fake rotate event
	resp = gwbuf_alloc(len + 5);
	hdr.payload_len = len + 1;
	hdr.seqno = slave->seqno++;
	hdr.ok = 0;
	hdr.timestamp = 0L;
	hdr.event_type = ROTATE_EVENT;
	hdr.serverid = router->masterid;
	hdr.event_size = len;
	hdr.next_pos = 0;
	hdr.flags = 0x20;
	ptr = blr_build_header(resp, &hdr);
	encode_value(ptr, slave->binlog_pos, 64);
	ptr += 8;
	memcpy(ptr, slave->binlogfile, binlognamelen);
	ptr += binlognamelen;

	if (!slave->nocrc)
	{
		/*
		 * Now add the CRC to the fake binlog rotate event.
		 *
		 * The algorithm is first to compute the checksum of an empty buffer
		 * and then the checksum of the event portion of the message, ie we do not
		 * include the length, sequence number and ok byte that makes up the first
		 * 5 bytes of the message. We also do not include the 4 byte checksum itself.
		 */
		chksum = crc32(0L, NULL, 0);
		chksum = crc32(chksum, GWBUF_DATA(resp) + 5, hdr.event_size - 4);
		encode_value(ptr, chksum, 32);
	}

	slave->dcb->func.write(slave->dcb, resp);
	return 1;
}
Пример #17
0
/**
 * We have a registered slave that is behind the current leading edge of the 
 * binlog. We must replay the log entries to bring this node up to speed.
 *
 * There may be a large number of records to send to the slave, the process
 * is triggered by the slave COM_BINLOG_DUMP message and all the events must
 * be sent without receiving any new event. This measn there is no trigger into
 * MaxScale other than this initial message. However, if we simply send all the
 * events we end up with an extremely long write queue on the DCB and risk
 * running the server out of resources.
 *
 * The slave catchup routine will send a burst of replication events per single
 * call. The paramter "long" control the number of events in the burst. The
 * short burst is intended to be used when the master receive an event and 
 * needs to put the slave into catchup mode. This prevents the slave taking
 * too much tiem away from the thread that is processing the master events.
 *
 * At the end of the burst a fake EPOLLOUT event is added to the poll event
 * queue. This ensures that the slave callback for processing DCB write drain
 * will be called and future catchup requests will be handled on another thread.
 *
 * @param	router		The binlog router
 * @param	slave		The slave that is behind
 * @param	large		Send a long or short burst of events
 * @return			The number of bytes written
 */
int
blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
{
GWBUF		*head, *record;
REP_HEADER	hdr;
int		written, rval = 1, burst;
int		rotating;
unsigned long	burst_size;
uint8_t		*ptr;

	if (large)
		burst = router->long_burst;
	else
		burst = router->short_burst;
	burst_size = router->burst_size;
	spinlock_acquire(&slave->catch_lock);
	if (slave->cstate & CS_BUSY)
	{
		spinlock_release(&slave->catch_lock);
		return 0;
	}
	slave->cstate |= CS_BUSY;
	spinlock_release(&slave->catch_lock);

	if (slave->file == NULL)
	{
		rotating = router->rotating;
		if ((slave->file = blr_open_binlog(router, slave->binlogfile)) == NULL)
		{
			if (rotating)
			{
				spinlock_acquire(&slave->catch_lock);
				slave->cstate |= CS_EXPECTCB;
				slave->cstate &= ~CS_BUSY;
				spinlock_release(&slave->catch_lock);
				poll_fake_write_event(slave->dcb);
				return rval;
			}
			LOGIF(LE, (skygw_log_write(
				LOGFILE_ERROR,
				"blr_slave_catchup failed to open binlog file %s",
					slave->binlogfile)));
			slave->cstate &= ~CS_BUSY;
			slave->state = BLRS_ERRORED;
			dcb_close(slave->dcb);
			return 0;
		}
	}
	slave->stats.n_bursts++;
	while (burst-- && burst_size > 0 &&
		(record = blr_read_binlog(router, slave->file, slave->binlog_pos, &hdr)) != NULL)
	{
		head = gwbuf_alloc(5);
		ptr = GWBUF_DATA(head);
		encode_value(ptr, hdr.event_size + 1, 24);
		ptr += 3;
		*ptr++ = slave->seqno++;
		*ptr++ = 0;		// OK
		head = gwbuf_append(head, record);
		if (hdr.event_type == ROTATE_EVENT)
		{
unsigned long beat1 = hkheartbeat;
			blr_close_binlog(router, slave->file);
if (hkheartbeat - beat1 > 1) LOGIF(LE, (skygw_log_write(
                                        LOGFILE_ERROR, "blr_close_binlog took %d beats",
				hkheartbeat - beat1)));
			blr_slave_rotate(slave, GWBUF_DATA(record));
beat1 = hkheartbeat;
			if ((slave->file = blr_open_binlog(router, slave->binlogfile)) == NULL)
			{
				if (rotating)
				{
					spinlock_acquire(&slave->catch_lock);
					slave->cstate |= CS_EXPECTCB;
					slave->cstate &= ~CS_BUSY;
					spinlock_release(&slave->catch_lock);
					poll_fake_write_event(slave->dcb);
					return rval;
				}
				LOGIF(LE, (skygw_log_write(
					LOGFILE_ERROR,
					"blr_slave_catchup failed to open binlog file %s",
					slave->binlogfile)));
				slave->state = BLRS_ERRORED;
				dcb_close(slave->dcb);
				break;
			}
if (hkheartbeat - beat1 > 1) LOGIF(LE, (skygw_log_write(
                                        LOGFILE_ERROR, "blr_open_binlog took %d beats",
				hkheartbeat - beat1)));
		}
		slave->stats.n_bytes += gwbuf_length(head);
		written = slave->dcb->func.write(slave->dcb, head);
		if (written && hdr.event_type != ROTATE_EVENT)
		{
			slave->binlog_pos = hdr.next_pos;
		}
		rval = written;
		slave->stats.n_events++;
		burst_size -= hdr.event_size;
	}
	if (record == NULL)
		slave->stats.n_failed_read++;
	spinlock_acquire(&slave->catch_lock);
	slave->cstate &= ~CS_BUSY;
	spinlock_release(&slave->catch_lock);

	if (record)
	{
		slave->stats.n_flows++;
		spinlock_acquire(&slave->catch_lock);
		slave->cstate |= CS_EXPECTCB;
		spinlock_release(&slave->catch_lock);
		poll_fake_write_event(slave->dcb);
	}
	else if (slave->binlog_pos == router->binlog_position &&
			strcmp(slave->binlogfile, router->binlog_name) == 0)
	{
		int state_change = 0;
		spinlock_acquire(&router->binlog_lock);
		spinlock_acquire(&slave->catch_lock);

		/*
		 * Now check again since we hold the router->binlog_lock
		 * and slave->catch_lock.
		 */
		if (slave->binlog_pos != router->binlog_position ||
			strcmp(slave->binlogfile, router->binlog_name) != 0)
		{
			slave->cstate &= ~CS_UPTODATE;
			slave->cstate |= CS_EXPECTCB;
			spinlock_release(&slave->catch_lock);
			spinlock_release(&router->binlog_lock);
			poll_fake_write_event(slave->dcb);
		}
		else
		{
			if ((slave->cstate & CS_UPTODATE) == 0)
			{
				slave->stats.n_upd++;
				slave->cstate |= CS_UPTODATE;
				spinlock_release(&slave->catch_lock);
				spinlock_release(&router->binlog_lock);
				state_change = 1;
			}
		}

		if (state_change)
		{
			slave->stats.n_caughtup++;
			if (slave->stats.n_caughtup == 1)
			{
				LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE,
					"%s: Slave %s is up to date %s, %u.",
					router->service->name,
					slave->dcb->remote,
					slave->binlogfile, slave->binlog_pos)));
			}
			else if ((slave->stats.n_caughtup % 50) == 0)
			{
				LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE,
					"%s: Slave %s is up to date %s, %u.",
					router->service->name,
					slave->dcb->remote,
					slave->binlogfile, slave->binlog_pos)));
			}
		}
	}
	else
	{
		if (slave->binlog_pos >= blr_file_size(slave->file)
				&& router->rotating == 0
				&& strcmp(router->binlog_name, slave->binlogfile) != 0
				&& blr_master_connected(router))
		{
			/* We may have reached the end of file of a non-current
			 * binlog file.
			 *
			 * Note if the master is rotating there is a window during
			 * which the rotate event has been written to the old binlog
			 * but the new binlog file has not yet been created. Therefore
			 * we ignore these issues during the rotate processing.
			 */
			LOGIF(LE, (skygw_log_write(LOGFILE_ERROR,
				"Slave reached end of file for binlong file %s at %u "
				"which is not the file currently being downloaded. "
				"Master binlog is %s, %lu.",
				slave->binlogfile, slave->binlog_pos,
				router->binlog_name, router->binlog_position)));
			if (blr_slave_fake_rotate(router, slave))
			{
				spinlock_acquire(&slave->catch_lock);
				slave->cstate |= CS_EXPECTCB;
				spinlock_release(&slave->catch_lock);
				poll_fake_write_event(slave->dcb);
			}
			else
			{
				slave->state = BLRS_ERRORED;
				dcb_close(slave->dcb);
			}
		}
		else
		{
			spinlock_acquire(&slave->catch_lock);
			slave->cstate |= CS_EXPECTCB;
			spinlock_release(&slave->catch_lock);
			poll_fake_write_event(slave->dcb);
		}
	}
	return rval;
}
Пример #18
0
	void encode_key(Buffer& buf, const KeyObject& key)
	{
		uint32 header = (uint32) (key.db << 8) + key.type;
		BufferHelper::WriteFixUInt32(buf, header);
		BufferHelper::WriteVarSlice(buf, key.key);
		switch (key.type)
		{
			case HASH_FIELD:
			{
				const HashKeyObject& hk = (const HashKeyObject&) key;
				BufferHelper::WriteVarSlice(buf, hk.field);
				break;
			}
			case LIST_ELEMENT:
			{
				const ListKeyObject& lk = (const ListKeyObject&) key;
				BufferHelper::WriteFixFloat(buf, lk.score);
				break;
			}
			case SET_ELEMENT:
			{
				const SetKeyObject& sk = (const SetKeyObject&) key;
				encode_value(buf, sk.value);
				break;
			}
			case ZSET_ELEMENT:
			{
				const ZSetKeyObject& sk = (const ZSetKeyObject&) key;
				BufferHelper::WriteFixDouble(buf, sk.score);
				encode_value(buf, sk.value);
				break;
			}
			case ZSET_ELEMENT_SCORE:
			{
				const ZSetScoreKeyObject& zk = (const ZSetScoreKeyObject&) key;
				encode_value(buf, zk.value);
				break;
			}
			case TABLE_INDEX:
			{
				const TableIndexKeyObject& index =
				        (const TableIndexKeyObject&) key;
				BufferHelper::WriteVarSlice(buf, index.colname);
				encode_value(buf, index.colvalue);
				BufferHelper::WriteVarUInt32(buf, index.index.size());
				ValueArray::const_iterator it = index.index.begin();
				while (it != index.index.end())
				{
					encode_value(buf, *it);
					it++;
				}
				break;
			}
			case TABLE_COL:
			{
				const TableColKeyObject& col = (const TableColKeyObject&) key;
				BufferHelper::WriteVarSlice(buf, col.colname);
				BufferHelper::WriteVarUInt32(buf, col.index.size());
				ValueArray::const_iterator it = col.index.begin();
				while (it != col.index.end())
				{
					encode_value(buf, *it);
					it++;
				}
				break;
			}
			case BITSET_ELEMENT:
			{
				const BitSetKeyObject& bk = (const BitSetKeyObject&) key;
				BufferHelper::WriteVarUInt64(buf, bk.index);
				break;
			}
			case KEY_EXPIRATION_ELEMENT:
			{
				const ExpireKeyObject& bk = (const ExpireKeyObject&) key;
				BufferHelper::WriteVarUInt64(buf, bk.expireat);
				break;
			}
			case LIST_META:
			case ZSET_META:
			case SET_META:
			case TABLE_META:
			case TABLE_SCHEMA:
			case BITSET_META:
			case KEY_EXPIRATION_MAPPING:
			case SCRIPT:
			default:
			{
				break;
			}
		}
	}
Пример #19
0
/**
 * Process a COM_BINLOG_DUMP message from the slave. This is the
 * final step in the process of registration. The new master, MaxScale
 * must send a response packet and generate a fake BINLOG_ROTATE event
 * with the binlog file requested by the slave. And then send a
 * FORMAT_DESCRIPTION_EVENT that has been saved from the real master.
 *
 * Once send MaxScale must continue to send binlog events to the slave.
 *
 * @param	router		The router instance
 * @param	slave		The slave server
 * @param	queue		The BINLOG_DUMP packet
 * @return			The number of bytes written to the slave
 */
static int
blr_slave_binlog_dump(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue)
{
GWBUF		*resp;
uint8_t		*ptr;
int		len, flags, serverid, rval, binlognamelen;
REP_HEADER	hdr;
uint32_t	chksum;

	ptr = GWBUF_DATA(queue);
	len = extract_field(ptr, 24);
	binlognamelen = len - 11;
	ptr += 4;		// Skip length and sequence number
	if (*ptr++ != COM_BINLOG_DUMP)
	{
        	LOGIF(LE, (skygw_log_write(
			LOGFILE_ERROR,
			"blr_slave_binlog_dump expected a COM_BINLOG_DUMP but received %d",
			*(ptr-1))));
		return 0;
	}

	slave->binlog_pos = extract_field(ptr, 32);
	ptr += 4;
	flags = extract_field(ptr, 16);
	ptr += 2;
	serverid = extract_field(ptr, 32);
	ptr += 4;
	strncpy(slave->binlogfile, (char *)ptr, binlognamelen);
	slave->binlogfile[binlognamelen] = 0;

	slave->seqno = 1;


	if (slave->nocrc)
		len = 19 + 8 + binlognamelen;
	else
		len = 19 + 8 + 4 + binlognamelen;

	// Build a fake rotate event
	resp = gwbuf_alloc(len + 5);
	hdr.payload_len = len + 1;
	hdr.seqno = slave->seqno++;
	hdr.ok = 0;
	hdr.timestamp = 0L;
	hdr.event_type = ROTATE_EVENT;
	hdr.serverid = router->masterid;
	hdr.event_size = len;
	hdr.next_pos = 0;
	hdr.flags = 0x20;
	ptr = blr_build_header(resp, &hdr);
	encode_value(ptr, slave->binlog_pos, 64);
	ptr += 8;
	memcpy(ptr, slave->binlogfile, binlognamelen);
	ptr += binlognamelen;

	if (!slave->nocrc)
	{
		/*
		 * Now add the CRC to the fake binlog rotate event.
		 *
		 * The algorithm is first to compute the checksum of an empty buffer
		 * and then the checksum of the event portion of the message, ie we do not
		 * include the length, sequence number and ok byte that makes up the first
		 * 5 bytes of the message. We also do not include the 4 byte checksum itself.
		 */
		chksum = crc32(0L, NULL, 0);
		chksum = crc32(chksum, GWBUF_DATA(resp) + 5, hdr.event_size - 4);
		encode_value(ptr, chksum, 32);
	}

	rval = slave->dcb->func.write(slave->dcb, resp);

	/* Send the FORMAT_DESCRIPTION_EVENT */
	if (slave->binlog_pos != 4)
		blr_slave_send_fde(router, slave);

	slave->dcb->low_water  = router->low_water;
	slave->dcb->high_water = router->high_water;
	dcb_add_callback(slave->dcb, DCB_REASON_DRAINED, blr_slave_callback, slave);
	slave->state = BLRS_DUMPING;

	LOGIF(LM, (skygw_log_write(
		LOGFILE_MESSAGE,
			"%s: New slave %s, server id %d,  requested binlog file %s from position %lu",
				router->service->name, slave->dcb->remote,
					slave->serverid,
					slave->binlogfile, slave->binlog_pos)));

	if (slave->binlog_pos != router->binlog_position ||
			strcmp(slave->binlogfile, router->binlog_name) != 0)
	{
		spinlock_acquire(&slave->catch_lock);
		slave->cstate &= ~CS_UPTODATE;
		slave->cstate |= CS_EXPECTCB;
		spinlock_release(&slave->catch_lock);
		poll_fake_write_event(slave->dcb);
	}
	return rval;
}