Libopensort
reference manual
|
for libopensort 0.5.1,
revision 1.
Table of contents
Overview - What is libopensort
Compiling - How to compile
libopensort
API - The application program interface
Utilities
Overview - What is libopensort
Libopensort is a general purpose library, which provides to
other programs an easy way to sort fast, data stored in one
or multiple files. Using different sorting algorithms, like
the stock qsort function provided by the standard C
library, or implementations of multithreaded qsort, as
well as monolithic and multithreaded MSB radix sort, gives
to the developer the ability to use the most efficient way
to sort the data in memory. In addition, libopensort gives
the option to use direct (unbuffered) I/O, or the zero copy
mechanism of the operating system, like the Linux splice (2)
system call. Following implementation paths related to
the hardware configuration, can push the I/O system to its
limits, and finally exploits the hardware to the full.
Libopensort is free and open-source software, distributed
under the terms of the GNU
GPL version 2 or later.
Compiling
-
How to compile libopensort
Build instructions about libopensort 0.5.1 can be found here.
API - The
application program interface
Basic concepts
Libopensort recognises two kinds of input files:
FLR: Binary fixed
length record where the record size is known in advance.
TEXT: Delimited text
(ASCII) where the record delimiter is always the standard
EOL sequence (usually LF or CRLF) of the operating system.
The column/field delimiter character is defined by the user.
Libopensort sorts the data in two phases, sort and merge.
During sort, it creates one thread for reading (the reader),
one for writing (the writer) and one or multiple threads for
data sorting (the sorters). Each sorter receives unsorted
data blocks from the reader and sends sorted data blocks to
the writer. Communication between reader, sorters and
writer, is achieved with the use of message queues. By the
end of the sort phase, there is one or multiple temporary
files which host all the records of the input files, sorted
in blocks.
During merge of FLR inputs, libopensort
creates one thread for prefetching microblocks from the
temporary file (the prefetcher), one for merging the records
(the merger) and one for writing (the writer). The merger
fills a binary tree requesting records from the prefetcher,
one for each block, extracts records from the tree in an
order complied with key definitions, and sends them to the
writer in blocks. Thus, by the end of the merge phase, there
is one or multiple files which host all the records of the
input files, fully sorted. Again, message queues are used
for the communication between prefetecher, merger and
writer.
Merge of TEXT inputs is more
simple. There is only one thread for reading and merging,
and no microblock prefetch, but only record fetch. The rest
of the merge mechanism remains the same.
Types
Types defined in libopensort header files.
Synopsis
Description
Types defined in opensort.h
Details
OPENSORT
Type of object holding information necessary to
control the sorting process.
os_error_t
typedef struct
{
const char *function;
char *opensort_error_str;
char *os_error_str;
char *source_file;
int opensort_errno;
int os_errno;
int error_line;
} os_error_t;
|
Type of object holding information about a runtime error.
function:
opensort_error_str:
os_error_str:
source_file:
opensort_errno:
os_errno:
error_line:
|
The function name
the error occured.
The string describing the error.
The string returned by strerror (3).
The source filename.
A value from opensort_errors.
The errno the operating system returned (may be
zero).
The line of the source file the error occured.
|
opensort_stats_t
typedef struct
{
struct timeval start;
struct timeval end;
struct timeval merge;
uint64_t bytes_read;
uint64_t bytes_written;
uint64_t prefetch_hits;
uint64_t prefetch_misses;
uint64_t records_in;
uint64_t records_out;
size_t memorypoolsize;
size_t threadmemoryspace;
size_t readbuffsize;
size_t microblocksize;
size_t mergerbuffsize;
size_t iosize;
int recordtype;
int sortpath;
int algorithm;
int sortmode;
int nuserkeys;
int nkeys;
int
nsorters;
int nblocks;
int nprefetchblocks;
int
mergeflag;
} opensort_stats_t;
|
Type of object holding statistics.
timeval start:
timeval end:
timeval merge:
bytes_read:
bytes_written:
prefetch_hits:
prefetch_misses:
records_in:
records_out:
memorypoolsize:
threadmemoryspace:
readbuffsize:
microblocksize:
mergerbuffsize:
iosize:
recordtype:
sortpath:
algorithm:
sortmode:
nuserkeys:
nkeys:
nsorters:
nblocks:
nprefetchblocks:
mergeflag:
|
Start time.
End time.
Merge start time.
Total bytes read.
Total bytes written.
Number of prefetch hits.
Number of prefetch misses.
Number of input records.
Number of output records.
Size of memory pool in bytes.
Memory space available to each sort thread in bytes.
Size of read buffer in bytes.
Size of microblock in bytes.
Size of merge buffer in bytes.
Size of I/O buffer in bytes.
OS_FLR or OS_TEXT.
OS_SORTER_PIPELINE,
OS_SORTER_DETACHED,
OS_SORTER_SEGMENTED
or OS_SORTER_MONOBLOCK.
OS_RADIX or OS_QSORT.
OS_SORTMODE_MONO or
OS_SORTMODE_MT.
Number of user defined keys.
Number of internal (consolidated) keys.
Number of sorters.
Number of sorted blocks.
Number of prefetch microblocks.
FALSE = sort/merge, TRUE = merge only.
|
Macros
Macros defined in libopensort header files.
Synopsis
Description
Commonly used macros in programs that use libopensort.
Details
Enumerated
types
Enums defined in libopensort header files.
Synopsis
#include <opensort.h>
typedef enum
{
OS_DUMMY,
OS_FLR,
OS_TEXT,
OS_STRING,
OS_STRING_IGNORE_CASE,
OS_NUMSTRING,
OS_FLOAT,
OS_DOUBLE,
OS_INT8,
OS_UINT8,
OS_INT16,
OS_UINT16,
OS_INT32,
OS_UINT32,
OS_INT64,
OS_UINT64,
OS_ASCENDING,
OS_DESCENDING,
OS_BUFFERED,
OS_UNBUFFERED,
OS_QSORT,
OS_RADIX,
OS_SORTER_PIPELINE,
OS_SORTER_DETACHED,
OS_SORTER_SEGMENTED,
OS_SORTER_MONOBLOCK,
OS_SORTMODE_MONO,
OS_SORTMODE_MT,
OS_PREFETCH_NONE,
OS_PREFETCH_CONSERVATIVE,
OS_PREFETCH_STANDARD,
OS_PREFETCH_AGGRESSIVE,
OS_IOMODE_SINGLE,
OS_IOMODE_MULTI,
OS_DELIM_SPACE,
OS_DELIM_TAB,
OS_DELIM_COLUMN,
OS_DELIM_SEMICOLUMN,
OS_DELIM_PIPE,
OS_DELIM_NONE,
OS_DELIM_COMMA
} opensort_flags;
typedef enum
{
OS_ERR_NONE,
OS_ERR_INV_PARAM,
OS_ERR_MEM,
OS_ERR_FILENAME,
OS_ERR_NOFLR,
OS_ERR_NOTEXT,
OS_ERR_VOLSIZE,
OS_ERR_INPUT_FILE,
OS_ERR_OUTPUT_FILE,
OS_ERR_OFFSET,
OS_ERR_TEXTKEY,
OS_ERR_KEYTYPE,
OS_ERR_DELIM,
OS_ERR_KEYORDER,
OS_ERR_STAT,
OS_ERR_READQUEUE,
OS_ERR_WRITEQUEUE,
OS_ERR_CREATEQUEUE,
OS_ERR_READ,
OS_ERR_WRITE,
OS_ERR_DEADTHREAD,
OS_ERR_NOKEYS
} opensort_errors;
|
Description
Libopensort defines two enumerated types: opensort_flags and opensort_errors. The elements
in opensort_flags are used as
function arguments and their meaning is explained below:
OS_DUMMY
OS_FLR
OS_TEXT
OS_STRING
OS_STRING_IGNORE_CASE
OS_NUMSTRING
OS_FLOAT
OS_DOUBLE
OS_INT8
OS_UINT8
OS_INT16
OS_UINT16
OS_INT32
OS_UINT32
OS_INT64
OS_UINT64
OS_ASCENDING
OS_DESCENDING
OS_BUFFERED
OS_UNBUFFERED
OS_SORTER_PIPELINE
OS_QSORT
OS_RADIX
OS_SORTER_DETACHED
OS_SORTER_SEGMENTED
OS_SORTER_MONOBLOCK
OS_SORTMODE_MONO
OS_SORTMODE_MT
OS_PREFETCH_CONSERVATIVE
OS_PREFETCH_STANDARD
OS_PREFETCH_AGGRESSIVE
OS_IOMODE_SINGLE
OS_IOMODE_MULTI
OS_DELIM_SPACE
OS_DELIM_TAB
OS_DELIM_COLUMN
OS_DELIM_SEMICOLUMN
OS_DELIM_PIPE
OS_DELIM_COMMA
OS_DELIM_NONE
OS_TEMPFILE_MULTIBLOCK
OS_TEMPFILE_SINGLEBLOCK
|
Dummy argument.
Input of fixed length records.
Input of delimited text lines.
Key type is string.
Key type is string but case will be ignored.
Key type is numeric string. String sorted according
to its numeric value.
Key type is native float.
Key type is native double.
Key type is native 8 bit signed integer.
Key type is native 8 bit unsigned integer.
Key type is native 16 bit signed integer.
Key type is native 16 bit unsigned integer.
Key type is native 32 bit signed integer.
Key type is native 32 bit unsigned integer.
Key type is native 64 bit signed integer.
Key type is native 64 bit unsigned integer.
Sort order is ascending.
Sort order is descending.
Buffered I/O.
Unbuffered (direct) I/O.
Pipeline sorter.
Algorithm: quicksort.
Algorithm: radix sort.
Detached sorter.
Segmented sorter.
Monoblock sorter.
Single threaded sorting algorithm.
Multithreaded sorting algorithm.
Conservative prefetch during merge.
Standard prefetch during merge.
Aggressive prefetch during merge.
Disable parallel I/O.
Enable parallel I/O.
Column delimiter is space character.
Column delimiter is tab character.
Column delimiter is column character.
Column delimiter is semicolumn character.
Column delimiter is pipe character.
Column delimiter is comma character.
Treat the whole line as one column.
Multi block temporary file.
Single block temporary file.
|
The elements in opensort_errors are used as
error codes and returned by functions of integer type. Their
meaning is explained below:
OS_ERR_NONE
OS_ERR_INV_PARAM
OS_ERR_MEM
OS_ERR_FILENAME
OS_ERR_NOFLR
OS_ERR_NOTEXT
OS_ERR_VOLSIZE
OS_ERR_INPUT_FILE
OS_ERR_OUTPUT_FILE
OS_ERR_OFFSET
OS_ERR_TEXTKEY
OS_ERR_KEYTYPE
OS_ERR_DELIM
OS_ERR_KEYORDER
OS_ERR_STAT
OS_ERR_READQUEUE
OS_ERR_WRITEQUEUE
OS_ERR_CREATEQUEUE
OS_ERR_READ
OS_ERR_WRITE
OS_ERR_DEADTHREAD
OS_ERR_NOKEYS
|
Function executed
normaly. No error found.
Invalid argument.
Not enough memory.
File name too long.
FLR key definition for TEXT initialized process.
TEXT key definition for FLR initialized process.
Volume size is negative.
Cannot open file for read.
Cannot open file for write.
Start offset greater than end offset in FLR key
definition.
Negative position in TEXT key definition.
Invalid key type.
Invalid delimiter.
Invalid key order.
Cannot stat file.
Cannot receive from message queue.
Cannot send to message queue.
Cannot create message queue.
Error during file read.
Error during file write.
Thread exited too early.
No keys defined.
|
Functions
Functions needed to use libopensort within a C program.
Synopsis
#include
<opensort.h>
|
|
|
|
OPENSORT
*opensort_init
|
(unsigned long
reservedbytes,
int recordtype,
size_t recordsize);
|
int opensort_addinputfile
|
(OPENSORT
* data,
char *filename,
int oflag);
|
int opensort_flraddkey
|
(OPENSORT
* data,
size_t startoff,
size_t endoff,
int keytype,
int order,
int dummy);
|
int opensort_textaddkey
|
(OPENSORT
* data,
int fieldpos,
int keytype,
int order);
|
int opensort_settextfielddelim
|
(OPENSORT
* data,
int delim);
|
int opensort_setoutputfile
|
(OPENSORT
* data,
char *filename,
off_t maxvolumesize,
int oflag);
|
int opensort_settempfile
|
(OPENSORT
* data,
char *filename,
int oflag,
int sflag);
|
void opensort_setnsorters
|
(OPENSORT
* data,
int nsorters);
|
void opensort_selectsorter
|
(OPENSORT
* data,
int hint);
|
void opensort_setprefetchpolicy
|
(OPENSORT
* data,
int policy);
|
void opensort_setiomode
|
(OPENSORT
* data,
int mode);
|
void opensort_setsortmode
|
(OPENSORT
* data,
int mode);
|
void opensort_setiobufsize
|
(OPENSORT
* data,
size_t iosize);
|
int opensort_sortmerge
|
(OPENSORT
* data,
int stableflag);
|
int opensort_merge
|
(OPENSORT
* data);
|
void opensort_statistics
|
(OPENSORT
* data,
opensort_stats_t
* stats);
|
void opensort_destroy
|
(OPENSORT
* data);
|
void opensort_version
|
(int *major,
int *minor,
int *patch);
|
os_error_t
*opensort_geterror
|
(OPENSORT
* data);
|
const char *opensort_strerror
|
(int OS_ERR);
|
Description
This section describes a number of functions implemented in
libopensort.
Details
opensort_init
()
OPENSORT * |
opensort_init |
(unsigned long
reservedbytes,
int recordtype,
size_t recordsize); |
Initializes the sort/merge process. This function must be
called first and only once before opensort_destroy ().
reservedbytes:
recordtype:
recordsize:
Returns:
|
Total RAM, in bytes,
dedicated for sort/merge process. Zero means 16 MB,
the default.
OS_FLR or OS_TEXT.
Record size for FLR,
ignored for TEXT.
An OPENSORT pointer or NULL
on failure.
|
opensort_addinputfile
()
int
|
opensort_addinputfile |
(OPENSORT
* data,
char *filename,
int oflag); |
Adds an input file in the input file list. This function may
be used multiple times if there are more than one input
files. All files will be processed FIFO.
opensort_setoutputfile
()
int
|
opensort_setoutputfile |
(OPENSORT
* data,
char *filename,
off_t maxvolumesize,
int oflag); |
Sets the output file. If the size of output file is greater
than maxvolumesize,
libopensort will create multiple files (volumes) with size
not greater than maxvolumesize.
No record will split between two volumes. Each volume cannot
be less than 256*1024 bytes. Maxvolumesize equal to 0 means no maximum.
data:
filename:
maxvolumesize:
oflag:
Returns:
|
OPENSORT
pointer returned by opensort_init
().
Full path of the output file.
Maximum size of each volume in bytes, or 0 if there
is no maximum. Values between 1 and 262143 will be
increased to 262144 (256K) silently.
OS_BUFFERED or OS_UNBUFFERED.
OS_ERR_NONE or an error code if an error
occured.
|
opensort_settempfile
()
int
|
opensort_settempfile |
(OPENSORT
* data,
char *filename,
int oflag,
int sflag); |
Sets the temporary file. If a call to this function is
absent, libopensort will create a temporary file in the
standard temporary directory. The temporary file will be
removed by the end of the sort process. If sflag is equal to
OS_TEMPFILE_SINGLEBLOCK, multiple temporary files will be
created, where each file will contain only one block.
opensort_flraddkey ()
int
|
opensort_flraddkey |
(OPENSORT
* data,
size_t startoff,
size_t endoff,
int keytype,
int order,
int dummy); |
Specifies a key in a FLR and adds it in
a key list. This function may be used multiple times if
there are more than one keys. All keys will be processed
FIFO.
data:
startoff:
endoff:
keytype:
order:
dummy:
Returns:
|
OPENSORT
pointer returned by opensort_init
().
Offset the key starts, count from 0.
Offset the key ends, count from 0.
Data type of the declared key. Valid values
are OS_STRING, OS_STRING_IGNORE_CASE,
OS_NUMSTRING, OS_FLOAT, OS_DOUBLE, OS_INT8, OS_UINT8,
OS_INT16, OS_UINT16, OS_INT32,
OS_UINT32, OS_INT64,
OS_UINT64.
Sort order of the key. Valid values are OS_ASCENDING or OS_DESCENDING.
A dummy argument. This is always OS_DUMMY.
OS_ERR_NONE or an error code if an error
occured.
|
opensort_settextfielddelim
()
int
|
opensort_settextfielddelim |
(OPENSORT
* data,
int delim); |
Sets a delimiter character which defines fields/columns in a
TEXT line.
opensort_textaddkey
()
int
|
opensort_textaddkey |
(OPENSORT
* data,
int fieldpos,
int keytype,
int order); |
Specifies a key in a TEXT line and adds
it in a key list. This function may be used multiple times
if there are more than one keys. All keys will be processed
FIFO.
opensort_setnsorters ()
void
|
opensort_setnsorters |
(OPENSORT
* data,
int nsorters); |
Sets the number of sorting threads. Any number above 8, will
be truncated to this limit.
data:
nsorters:
Returns:
|
OPENSORT
pointer returned by opensort_init
().
Number of sorting threads. Maximum is 8.
Nothing.
|
opensort_selectsorter
()
void
|
opensort_selectsorter |
(OPENSORT
* data,
int hint); |
Gives a hint about the sorter to be used. Libopensort may
ignore it and fall back to default. If a call to this
function is absent, the default sorter will be used. Valid
hint values are the following:
OS_SORTER_DETACHED: |
Use the detached
sorter. This is the default sorter, able to cover
all possible key type and order combinations,
performing parallel I/O.
|
OS_SORTER_PIPELINE: |
Use the pipeline
sorter. This is a three stage pipeline: read, sort
and write. This sorter will perform parallel I/O,
optimized for multi disk/array systems, where
temporary file lays on a different physical
media than input and output files.
|
OS_SORTER_SEGMENTED: |
Use the segmented
sorter. This sorter is optimized for RAM or CPU
bound hardware and will perform limited parallel
I/O. Performs better in single disk/array systems or
when temporary file lays on the same physical
media with input and output files.
|
OS_SORTER_MONOBLOCK:
|
Use the monoblock
sorter. With this sorter no parallel I/O is
performed, unless opensort_setnsorters
() has set more than one sorters. Targets to systems
with deep multithreading capabilities, vast amounts
of RAM and high storage throughput.
|
opensort_setprefetchpolicy
()
void
|
opensort_setprefetchpolicy |
(OPENSORT
* data,
int policy); |
Sets the microblock prefetch policy to be used during merge.
If a call to this function is absent, microblock prefetching
is disabled.
opensort_setiomode ()
void
|
opensort_setiomode |
(OPENSORT
* data,
int mode); |
Sets the operating mode for single or multi disc/array
systems. When set to OS_IOMODE_SINGLE, read blocks write and
vice versa. If a call to this function is absent,
OS_IOMODE_MULTI is used.
opensort_setsortmode ()
void
|
opensort_setsortmode |
(OPENSORT
* data,
int mode); |
Orders the sorter to use a monolithic or a multithreaded
implementation of sort function, if this is possible. If a
call to this function is absent, a single threaded
implementation is used.
opensort_setiobufsize ()
void
|
opensort_setiobufsize |
(OPENSORT
* data,
size_t iosize); |
Sets the size of read and write buffers. If a call to this
function is absent, 4096 bytes will be used for each buffer.
data:
iosize:
Returns:
|
OPENSORT
pointer returned by opensort_init
().
Size of each I/O buffer in bytes.
Nothing.
|
opensort_sortmerge ()
int
|
opensort_sortmerge |
(OPENSORT
* data,
int stableflag); |
Performs sort/merge.
opensort_merge
()
Performs merge of already sorted inputs.
opensort_statistics ()
Get the statistics collected during sort and merge.
opensort_destroy
()
void
|
opensort_destroy |
(OPENSORT
* data); |
Finalizes the process, releasing all memory and disc space
used.
opensort_version
()
void
|
opensort_version
|
(int *major,
int *minor,
int *patch);
|
Get library version.
major:
minor:
patch:
Returns:
|
Library version major
number.
Library version minor number.
Library version patch number.
Nothing.
|
opensort_geterror
()
Gives access to error list. This is useful if opensort_sortmerge ()
returned with an error, in any other case, it returns NULL.
opensort_strerror
()
const char *
|
opensort_geterror
|
(int OS_ERR);
|
Returns a string describing a value from opensort_errors.
OS_ERR:
Returns:
|
A value from opensort_errors.
A string describing an error number or NULL if
OS_ERR is invalid.
|
Examples
Example for binary FLR sort.
#include <stdio.h>
#include <opensort.h>
#define MEGABYTE (1024*1024)
#define KILOBYTE 1024
int
main ()
{
OPENSORT *sort;
int result;
/*
Initialize for 32 MB available RAM and 298 bytes
record size */
sort = opensort_init
(32 * MEGABYTE, OS_FLR, 298);
if (sort == NULL)
{
printf ("Opensort
initialization failed\n");
return 0;
}
/* Add an
input file for direct I/O */
result = opensort_addinputfile
(sort, "input.dat", OS_UNBUFFERED);
if (result != OS_ERR_NONE)
{
printf ("Cannot add
input file\n");
goto end;
}
/* Set an
output file for direct I/O. It will split in
volumes of 10,000 records each */
result =
opensort_setoutputfile
(sort, "output.dat", 2980000, OS_UNBUFFERED);
if (result != OS_ERR_NONE)
{
printf ("Cannot set
output file\n");
goto end;
}
/* Add the
first key. From offset 37 to 40, ascending
character */
result =
opensort_flraddkey
(sort, 37, 40, OS_STRING,
OS_ASCENDING, OS_DUMMY);
if (result != OS_ERR_NONE)
{
printf ("Cannot add
the first key\n");
goto end;
}
/* Add the
second key. From offset 97 to 111, descending
numeric string */
result =
opensort_flraddkey
(sort, 97, 111, OS_NUMSTRING,
OS_DESCENDING, OS_DUMMY);
if (result != OS_ERR_NONE)
{
printf ("Cannot add
the second key\n");
goto end;
}
/* Set
prefetch policy and the size of I/O buffers
*/
opensort_setprefetchpolicy
(sort, OS_PREFETCH_CONSERVATIVE);
opensort_setiobufsize
(sort, 64 * KILOBYTE);
/* Proceed
to sort/merge */
result = opensort_sortmerge
(sort, FALSE);
if (result != OS_ERR_NONE)
printf ("Runtime Error: %s\n", opensort_strerror
(result));
end:
/* Release
all allocated RAM and delete temporary file(s) */
opensort_destroy
(sort);
return 0;
}
|
Example for TEXT sort.
#include <stdio.h>
#include <opensort.h>
#define MEGABYTE (1024*1024)
#define KILOBYTE 1024
int
main ()
{
OPENSORT *sort;
int result;
/*
Initialize for 32 MB available RAM */
sort = opensort_init
(32 * MEGABYTE, OS_TEXT, 0);
if (sort == NULL)
{
printf ("Opensort
initialization failed\n");
return 0;
}
/* Add an
input file */
result = opensort_addinputfile
(sort, "input.txt", OS_BUFFERED);
if (result != OS_ERR_NONE)
{
printf ("Cannot add
input file\n");
goto end;
}
/* Set the
output file */
result = opensort_setoutputfile
(sort, "output.txt", 0, OS_BUFFERED);
if (result != OS_ERR_NONE)
{
printf ("Cannot set
output file\n");
goto end;
}
/*
Delimiter is pipe */
result = opensort_settextfielddelim
(sort, OS_DELIM_PIPE);
if (result != OS_ERR_NONE)
{
printf ("Cannot set
delimiter\n");
goto end;
}
/* Add the
first key. Column 3, ascending character */
result = opensort_textaddkey
(sort, 3, OS_STRING, OS_ASCENDING);
if (result != OS_ERR_NONE)
{
printf ("Cannot add
the first key\n");
goto end;
}
/* Add the
second key. Column 9, descending numeric */
result = opensort_textaddkey
(sort, 9, OS_NUMSTRING,
OS_DESCENDING);
if (result != OS_ERR_NONE)
{
printf ("Cannot add
the second key\n");
goto end;
}
/* Set size
of I/O buffers */
opensort_setiobufsize
(sort, 8 * KILOBYTE);
/* Proceed
to sort/merge. Keep duplicates in order */
result = opensort_sortmerge
(sort, TRUE);
if (result != OS_ERR_NONE)
{
os_error_t
*err;
printf ("Runtime Error:
%s\n", opensort_strerror
(result));
/* Print
contents of error list */
err = opensort_geterror
(sort);
while (err != NULL)
{
printf
(">Error in function: %s\n", err->function);
printf (" From
source: %s at line: %d\n", err->source_file,
err->error_line);
printf ("
Operating system returned: %s\n",
err->os_error_str);
printf ("
libopensort returned: %s\n",
err->opensort_error_str);
err = opensort_geterror
(sort);
}
}
end:
/* Release
all allocated RAM and delete temporary file(s) */
opensort_destroy
(sort);
return 0;
}
|
Utilities
Opensort
Opensort is a command line utility built around libopensort.
More information about opensort can be found here.
|