int gfs_read_batched(int fork_id, char *buf, struct gfs_batch vector, int quant);
int gfs_nb_read_batched(gfs_handle handle, int fork_id, char *buf, struct gfs_batch vector, int quant);
int gfs_write_batched(int fork_id, char *buf, struct gfs_batch vector, int quant);
int gfs_nb_write_batched(gfs_handle handle, int fork_id, char *buf, struct gfs_batch vector, int quant);
struct gfs_batch {
int32 f_off;
int32 m_off;
char f_absolute;
char m_absolute;
char sub_vector;
int32 quant;
int32 f_stride;
int32 m_stride;
int32 subvec_len;
union {
int32 size;
struct gfs_batch *subvec;
} sub;
};
A single instance of this data structure essentially represents a single level in a nested-strided request. That is, with one gfs_batch structure, you can represent a ``standard'' request, a simple-strided request, or one level of nesting in a nested-strided request. Galley's batched interface allows an application to submit a vector of batched requests, which allows an application to submit a list of strided requests, a list of standard requests, a list of nested-strided requests, or arbitrarily complex combinations of those requests.
As with a nested-strided request, a batched request allows an application to specify that a particular pattern will be repeated a number of times, with a regular stride between each instance of the pattern. However, a nested-strided request requires that the repeated pattern be either a simple- or a nested-strided requests. The batched interface allows applications to repeat batched requests with a regular stride between them. Hence the name ``nestedbatched''. This capability allows applications to repeat arbitrary access patterns with a regular stride.
A full gfs_read_batched() or gfs_write_batched() request will typically combine multiple gfs_batch structures into vectors, trees, vectors of trees, trees of vectors, and so on. For example, a doubly-nested-strided request would be a two-level tree. The root of the tree would describe the outer level of striding, and that node's child would describe the inner level of striding. An application with two such strided requests could combine them into a single batched request. In that case, there would be a vector of two trees, and each tree would have two levels.
The first two elements in the data structure contain the initial file and memory offsets of the request. The second two elements of the data structure indicate whether these offsets are specified absolutely (as is done with all other Galley requests), or relatively. If the offsets are relative, then if the request is the first element in a new vector, these offsets are specified relative to the offset of that vector's parent. Otherwise, a relative offset is specified relative to the offset of the previous element in the vector.
The fifth element in the structure (sub_vector) indicates whether the pattern to be repeated is a simple data request or another batch vector. The sixth element (quant) indicates how many times the pattern should be repeated. The next two elements contain the strides that should be applied to the file and memory offsets between repetitions of the pattern. The ninth element in the structure only applies when the pattern to be repeated is a batched request. In that case, it indicates how many elements are in the sub-request.
Finally, the sub-request is described. The sub-request can be a simple data transfer (in the case of a standard or a simple-strided request), or it can be a vector of gfs_batch structures (in the case of a nested-strided, or more complex request).
gfs_read_batched and gfs_write_batched are blocking calls, so they will not return until all the data has actually been transferred.
gfs_nb_read_batched and gfs_nb_write_batched are nonblocking calls, so they will return immediately. The application can call gfs_test(handle) to determine whether or not all the data has been transferred. The application must call gfs_wait(handle) before handle may be used in another non-blocking call.