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); }
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; }