Exemplo n.º 1
0
USHORT REMOTE_compute_batch_size(rem_port* port,
								 USHORT buffer_used, P_OP op_code,
								 const rem_fmt* format)
{
/**************************************
 *
 *	R E M O T E _ c o m p u t e _ b a t c h _ s i z e
 *
 **************************************
 *
 * Functional description
 *
 * When batches of records are returned, they are returned as
 *    follows:
 *     <op_fetch_response> <data_record 1>
 *     <op_fetch_response> <data_record 2>
 * 	...
 *     <op_fetch_response> <data_record n-1>
 *     <op_fetch_response> <data_record n>
 *
 * end-of-batch is indicated by setting p_sqldata_messages to
 * 0 in the op_fetch_response.  End of cursor is indicated
 * by setting p_sqldata_status to a non-zero value.  Note
 * that a fetch CAN be attempted after end of cursor, this
 * is sent to the server for the server to return the appropriate
 * error code.
 *
 * Each data block has one overhead packet
 * to indicate the data is present.
 *
 * (See also op_send in receive_msg() - which is a kissing cousin
 *  to this routine)
 *
 * Here we make a guess for the optimal number of records to
 * send in each batch.  This is important as we wait for the
 * whole batch to be received before we return the first item
 * to the client program.  How many are cached on the client also
 * impacts client-side memory utilization.
 *
 * We optimize the number by how many can fit into a packet.
 * The client calculates this number (n from the list above)
 * and sends it to the server.
 *
 * The data size is either the XDR data representation, or the
 * actual message size (rounded up) if this is a symmetric
 * architecture connection.
 *
 **************************************/

	const USHORT op_overhead = (USHORT) xdr_protocol_overhead(op_code);

#ifdef DEBUG
	fprintf(stderr,
			   "port_buff_size = %d fmt_net_length = %d fmt_length = %d overhead = %d\n",
			   port->port_buff_size, format->fmt_net_length,
			   format->fmt_length, op_overhead);
#endif

	const ULONG row_size = op_overhead +
		(port->port_flags & PORT_symmetric) ?
			ROUNDUP(format->fmt_length, 4) : 	// Same architecture connection
			ROUNDUP(format->fmt_net_length, 4);	// Using XDR for data transfer

	ULONG result = (port->port_protocol >= PROTOCOL_VERSION13) ?
		MAX_ROWS_PER_BATCH : (MAX_PACKETS_PER_BATCH * port->port_buff_size - buffer_used) / row_size;

	// Don't ask for more records than we can cache

	result = MIN(result, MAX_BATCH_CACHE_SIZE / format->fmt_length);

	// Must always send some messages, even if message is larger than packet

	result = MAX(result, MIN_ROWS_PER_BATCH);

	fb_assert(result <= MAX_USHORT);
	return static_cast<USHORT>(result);
}
Exemplo n.º 2
0
ULONG REMOTE_compute_batch_size(rem_port* port,
								USHORT buffer_used, P_OP op_code,
								const rem_fmt* format)
{
/**************************************
 *
 *	R E M O T E _ c o m p u t e _ b a t c h _ s i z e
 *
 **************************************
 *
 * Functional description
 *
 * When batches of records are returned, they are returned as
 *    follows:
 *     <op_fetch_response> <data_record 1>
 *     <op_fetch_response> <data_record 2>
 * 	...
 *     <op_fetch_response> <data_record n-1>
 *     <op_fetch_response> <data_record n>
 *
 * end-of-batch is indicated by setting p_sqldata_messages to
 * 0 in the op_fetch_response.  End of cursor is indicated
 * by setting p_sqldata_status to a non-zero value.  Note
 * that a fetch CAN be attempted after end of cursor, this
 * is sent to the server for the server to return the appropriate
 * error code.
 *
 * Each data block has one overhead packet
 * to indicate the data is present.
 *
 * (See also op_send in receive_msg() - which is a kissing cousin
 *  to this routine)
 *
 * Here we make a guess for the optimal number of records to
 * send in each batch.  This is important as we wait for the
 * whole batch to be received before we return the first item
 * to the client program.  How many are cached on the client also
 * impacts client-side memory utilization.
 *
 * We optimize the number by how many can fit into a packet.
 * The client calculates this number (n from the list above)
 * and sends it to the server.
 *
 * I asked why it is that the client doesn't just ask for a packet
 * full of records and let the server return however many fits in
 * a packet.  According to Sudesh, this is because of a bug in
 * Superserver which showed up in the WIN_NT 4.2.x kits.  So I
 * imagine once we up the protocol so that we can be sure we're not
 * talking to a 4.2 kit, then we can make this optimization.
 *           - Deej 2/28/97
 *
 * Note: A future optimization can look at setting the packet
 * size to optimize the transfer.
 *
 * Note: This calculation must use worst-case to determine the
 * packing.  Should the data record have VARCHAR data, it is
 * often possible to fit more than the packing specification
 * into each packet.  This is also a candidate for future
 * optimization.
 *
 * The data size is either the XDR data representation, or the
 * actual message size (rounded up) if this is a symmetric
 * architecture connection.
 *
 **************************************/

	const USHORT MAX_PACKETS_PER_BATCH	= 4;	// packets    - picked by SWAG
	const USHORT MIN_PACKETS_PER_BATCH	= 2;	// packets    - picked by SWAG
	const USHORT DESIRED_ROWS_PER_BATCH	= 20;	// data rows  - picked by SWAG
	const USHORT MIN_ROWS_PER_BATCH		= 10;	// data rows  - picked by SWAG

	const USHORT op_overhead = (USHORT) xdr_protocol_overhead(op_code);

#ifdef DEBUG
	fprintf(stderr,
			   "port_buff_size = %d fmt_net_length = %d fmt_length = %d overhead = %d\n",
			   port->port_buff_size, format->fmt_net_length,
			   format->fmt_length, op_overhead);
#endif

	ULONG row_size;
	if (port->port_flags & PORT_symmetric)
	{
		// Same architecture connection
		row_size = (ROUNDUP(format->fmt_length, 4) + op_overhead);
	}
	else
	{
		// Using XDR for data transfer
		row_size = (ROUNDUP(format->fmt_net_length, 4) + op_overhead);
	}

	USHORT num_packets = (USHORT) (((DESIRED_ROWS_PER_BATCH * row_size)	// data set
							 + buffer_used	// used in 1st pkt
							 + (port->port_buff_size - 1))	// to round up
							/ port->port_buff_size);
	if (num_packets > MAX_PACKETS_PER_BATCH)
	{
		num_packets = (USHORT) (((MIN_ROWS_PER_BATCH * row_size)	// data set
								 + buffer_used	// used in 1st pkt
								 + (port->port_buff_size - 1))	// to round up
								/ port->port_buff_size);
	}
	num_packets = MAX(num_packets, MIN_PACKETS_PER_BATCH);

	// Now that we've picked the number of packets in a batch,
	// pack as many rows as we can into the set of packets

	ULONG result = (num_packets * port->port_buff_size - buffer_used) / row_size;

	// Must always send some messages, even if message size is more
	// than packet size.

	result = MAX(result, MIN_ROWS_PER_BATCH);

#ifdef DEBUG
	{
		// CVC: I don't see the point in replacing this with fb_utils::readenv().
		const char* p = getenv("DEBUG_BATCH_SIZE");
		if (p)
			result = atoi(p);
		fprintf(stderr, "row_size = %lu num_packets = %d\n", row_size, num_packets);
		fprintf(stderr, "result = %lu\n", result);
	}
#endif

	return result;
}