Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2300 lines
71 KiB

  1. /* SORT.C
  2. *
  3. * This is rewrite of the NT sort program achieves two goals:
  4. * 1) improves the general speed of the sort program.
  5. * 2) performs two-pass sort so that large data sets can be sorted.
  6. *
  7. * It is designed for a single-disk environment.
  8. *
  9. * Author: Chris Nyberg
  10. * Ordinal Technology Corp, under contract to Microsoft Corporation
  11. * Dec 1997
  12. */
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <windows.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <wchar.h>
  21. #include <windows.h>
  22. #include <mbctype.h>
  23. #include <locale.h>
  24. #include <tchar.h>
  25. #include <assert.h>
  26. #include <limits.h>
  27. #include <winnlsp.h>
  28. #include "sortmsg.h"
  29. #define ROUND_UP(a, b) ((((a) + (b) - 1) / (b)) * (b))
  30. #define ROUND_DOWN(a, b) (((a) / (b)) * (b))
  31. #define CTRL_Z '\x1A'
  32. #define MAX_IO 2 /* the maximum number of r/w requests per file */
  33. #define N_RUN_BUFS 2 /* read buffers per run during merge phase */
  34. #define MAX_XFR_SIZE (1 << 18) /* maximum i/o transfer size */
  35. #define MIN_MEMORY_SIZE (160 * 1024) /* minimum memory size to use */
  36. #ifdef UNICODE
  37. #define ANSI_TO_TCHAR(a) ansi_to_wchar(a)
  38. #else
  39. #define ANSI_TO_TCHAR(a) (a)
  40. #endif
  41. char *Locale; /* Locale argument */
  42. int Max_rec_length = 4096; /* maximum characters in a record */
  43. int Max_rec_bytes_internal; /* max bytes for a internally-stored record */
  44. int Max_rec_bytes_external; /* max bytes for a record to/from a file */
  45. BOOL Reverse; /* the /R argument to reverse the sort order. */
  46. BOOL Case_sensitive; /* make comparisons case sensitive */
  47. BOOL UnicodeOut; /* Write the output file in unicode. */
  48. int Position; /* the /+n argument to skip characters at the
  49. * beginning of each record. */
  50. enum { /* the type of characters in the input and output */
  51. CHAR_SINGLE_BYTE, /* internally stored as single-byte chars */
  52. CHAR_MULTI_BYTE, /* internally stored as unicode */
  53. CHAR_UNICODE /* internally stored as unicode */
  54. } Input_chars, Output_chars;
  55. int (_cdecl *Compare)(const void *, const void *); /* record comparison */
  56. char *Alloc_begin; /* the beginning for VirtualAlloc()'ed memory */
  57. TCHAR *Input_name; /* input file name, NULL if standard input */
  58. HANDLE Input_handle; /* input file handle */
  59. BOOL Input_un_over; /* input file handle is unbuffered and overlapped */
  60. int Input_type; /* input from disk, pipe, or char (console)? */
  61. int In_max_io = 1; /* max number of input read requests */
  62. __int64 Input_size = -1; /* the size of the input file, -1 if unknown. */
  63. __int64 Input_scheduled;/* number of bytes scheduled for reading so far. */
  64. __int64 Input_read; /* number of bytes read so far. */
  65. int Input_read_size;/* the number of bytes to read for each ReadFile() */
  66. char *In_buf[MAX_IO];/* Input buffer(s) */
  67. int Input_buf_size; /* size of input buffer(s) */
  68. char *In_buf_next; /* Next byte to remove from input buffer */
  69. char *In_buf_limit; /* Limit of valid bytes in input buffer */
  70. char *Next_in_byte; /* Next input byte */
  71. BOOL EOF_seen; /* has eof been seen? */
  72. int Reads_issued; /* the number of reads issued to either the
  73. * input file or temporary file */
  74. int Reads_completed;/* the number of reads completed to either the
  75. * input file or temporary file */
  76. SYSTEM_INFO Sys;
  77. MEMORYSTATUSEX MemStat;
  78. CPINFO CPInfo;
  79. unsigned Memory_limit; /* limit on the amount of process memory used */
  80. unsigned User_memory_limit; /* user-specified limit */
  81. #define TEMP_LENGTH 1000
  82. TCHAR Temp_name[TEMP_LENGTH];
  83. TCHAR *Temp_dir; /* temporary directory specified by user */
  84. HANDLE Temp_handle; /* temporary file handle */
  85. int Temp_sector_size; /* sector size on temporary disks */
  86. int Temp_buf_size; /* size of temp file xfers */
  87. void *Rec_buf; /* Record buffer */
  88. int Rec_buf_bytes; /* Number of bytes currently in the record buffer */
  89. TCHAR *Output_name; /* output file name, NULL if standard output */
  90. HANDLE Output_handle; /* output file handle */
  91. BOOL Output_un_over; /* output file handle is unbuffered and overlapped */
  92. int Output_type; /* output to disk, pipe, or char (console)? */
  93. int Output_sector_size; /* size of a sector on the output device */
  94. int Out_max_io = 1; /* max number of output write requests */
  95. int Out_buf_bytes; /* number of bytes in the current output buffer */
  96. int Out_buf_size; /* buffer size of the current output stream: either
  97. * the temp file or output file */
  98. char *Out_buf[MAX_IO];
  99. int Output_buf_size;/* size of output buffer(s) */
  100. int Writes_issued; /* the number of writes issued to either the
  101. * temporary file or the output file */
  102. int Writes_completed; /* the number of writes completed to either the
  103. * temporary file or the output file */
  104. __int64 Out_offset; /* current output file offset */
  105. enum {
  106. INPUT_PHASE,
  107. OUTPUT_PHASE
  108. } Phase;
  109. int Two_pass; /* non-zero if two-pass, zero of one-pass */
  110. char *Merge_phase_run_begin; /* address of run memory during merge phase */
  111. char *Rec; /* internal record buffer */
  112. char *Next_rec; /* next insertion point in internal record buffer */
  113. char **Last_recp; /* next place to put a (not short) record ptr */
  114. char **Short_recp; /* last short record pointer */
  115. char **End_recp; /* end of record pointer array */
  116. OVERLAPPED Over;
  117. typedef struct
  118. {
  119. int requested; /* bytes requested */
  120. int completed; /* bytes completed */
  121. OVERLAPPED over;
  122. } async_t;
  123. async_t Read_async[MAX_IO];
  124. async_t Write_async[MAX_IO];
  125. typedef struct run
  126. {
  127. int index; /* index of this run */
  128. __int64 begin_off; /* beginning offset of run in temp file */
  129. __int64 mid_off; /* mid-point offset between normal and
  130. * short records for this run in temp file */
  131. __int64 end_off; /* ending offset of run in temp file */
  132. char *buf[N_RUN_BUFS]; /* bufs to hold blocks read from temp file */
  133. char *buf_begin; /* beginning of block buffer being read from */
  134. __int64 buf_off; /* offset in temp file of block in buf */
  135. int buf_bytes; /* number of bytes in buffer */
  136. char *next_byte; /* next byte to be read from buffer */
  137. __int64 end_read_off; /* end read offset */
  138. char *rec; /* record buffer */
  139. int blks_read; /* count of blocks that have been read */
  140. int blks_scanned; /* count of blocks that have been scanned */
  141. struct run *next; /* next run in block read queue */
  142. } run_t;
  143. #define NULL_RUN ((run_t *)NULL)
  144. #define END_OF_RUN ((run_t *)-1)
  145. run_t *Run; /* array of run structs */
  146. run_t **Tree; /* merge phase tournament tree */
  147. unsigned int N_runs; /* number of runs written to temporary file */
  148. unsigned int Run_limit; /* limit on number of runs set dictated
  149. * by memory size */
  150. /* the run read queue is a queue of runs that have an empty buffer which
  151. * should be filled with the next block of data for that run.
  152. */
  153. run_t *Run_read_head;
  154. run_t *Run_read_tail;
  155. #define MESSAGE_BUFFER_LENGTH 8192
  156. /* SYS_ERROR - print the string for an NT error code and exit.
  157. */
  158. void
  159. sys_error(TCHAR *str, int error)
  160. {
  161. LPSTR lpMsgBuf;
  162. DWORD bytes;
  163. wchar_t *w_str;
  164. NTSTATUS status;
  165. char messageBuffer[MESSAGE_BUFFER_LENGTH];
  166. if (str != NULL) {
  167. bytes = strlen( str );
  168. w_str = HeapAlloc(GetProcessHeap(), 0, (bytes+1) * sizeof(wchar_t));
  169. if ( w_str ) {
  170. status = RtlMultiByteToUnicodeN(w_str,
  171. bytes * sizeof(wchar_t),
  172. &bytes,
  173. str,
  174. bytes );
  175. if ( NT_SUCCESS(status) ) {
  176. status = RtlUnicodeToOemN(messageBuffer,
  177. MESSAGE_BUFFER_LENGTH-1,
  178. &bytes,
  179. w_str,
  180. bytes );
  181. if ( NT_SUCCESS(status) ) {
  182. messageBuffer[bytes] = 0;
  183. fprintf(stderr, messageBuffer);
  184. }
  185. }
  186. HeapFree(GetProcessHeap(), 0, w_str);
  187. }
  188. }
  189. if (error == 0)
  190. error = GetLastError();
  191. bytes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  192. FORMAT_MESSAGE_FROM_SYSTEM |
  193. FORMAT_MESSAGE_IGNORE_INSERTS,
  194. GetModuleHandle(NULL),
  195. error,
  196. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
  197. (LPSTR) &lpMsgBuf,
  198. 0,
  199. NULL);
  200. w_str = HeapAlloc(GetProcessHeap(), 0, (bytes+1) * sizeof(wchar_t));
  201. if ( w_str ) {
  202. status = RtlMultiByteToUnicodeN(w_str,
  203. bytes * sizeof(wchar_t),
  204. &bytes,
  205. lpMsgBuf,
  206. bytes );
  207. if ( NT_SUCCESS(status) ) {
  208. status = RtlUnicodeToOemN(messageBuffer,
  209. MESSAGE_BUFFER_LENGTH-1,
  210. &bytes,
  211. w_str,
  212. bytes );
  213. if ( NT_SUCCESS(status) ) {
  214. messageBuffer[bytes] = 0;
  215. fprintf(stderr, messageBuffer);
  216. }
  217. }
  218. }
  219. exit(EXIT_FAILURE);
  220. }
  221. /* GET_STRING - get a string from the sort program's string table.
  222. */
  223. TCHAR *get_string(int id)
  224. {
  225. wchar_t *w_str;
  226. DWORD bytes;
  227. NTSTATUS status;
  228. static char messageBuffer[MESSAGE_BUFFER_LENGTH] = "";
  229. bytes = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
  230. NULL,
  231. id,
  232. 0,
  233. messageBuffer,
  234. MESSAGE_BUFFER_LENGTH,
  235. NULL );
  236. w_str = HeapAlloc(GetProcessHeap(), 0, (bytes+1) * sizeof(wchar_t));
  237. if ( w_str ) {
  238. status = RtlMultiByteToUnicodeN(w_str,
  239. bytes * sizeof(wchar_t),
  240. &bytes,
  241. messageBuffer,
  242. bytes );
  243. if ( NT_SUCCESS(status) ) {
  244. status = RtlUnicodeToOemN(messageBuffer,
  245. MESSAGE_BUFFER_LENGTH-1,
  246. &bytes,
  247. w_str,
  248. bytes );
  249. if ( NT_SUCCESS(status) ) {
  250. messageBuffer[bytes] = 0;
  251. }
  252. }
  253. }
  254. return (messageBuffer);
  255. }
  256. /* USAGE - print the /? usage message to the standard output.
  257. */
  258. void usage()
  259. {
  260. DWORD bytes;
  261. fprintf(stdout, "%s", get_string(MSG_SORT_USAGE1));
  262. fprintf(stdout, "%s\n", get_string(MSG_SORT_USAGE2));
  263. exit (0);
  264. }
  265. /* WARNING - print a warning string from the sort program's string table.
  266. */
  267. void warning(int id)
  268. {
  269. fprintf(stderr, "%s\n", get_string(id));
  270. return;
  271. }
  272. /* ERROR - print an error string from the string table and exit.
  273. */
  274. void error(int id)
  275. {
  276. fprintf(stderr, "%s\n", get_string(id));
  277. exit (EXIT_FAILURE);
  278. }
  279. /* ANSI_TO_WCHAR - convert and ansi string to unicode.
  280. */
  281. wchar_t *ansi_to_wchar(char *str)
  282. {
  283. int n_wchars;
  284. wchar_t *w_str;
  285. n_wchars = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
  286. w_str = HeapAlloc(GetProcessHeap(), 0, n_wchars * sizeof(wchar_t));
  287. if ( w_str ) {
  288. MultiByteToWideChar(CP_ACP, 0, str, -1, w_str, n_wchars);
  289. }
  290. return (w_str);
  291. }
  292. /* READ_ARGS - process the command line arguments.
  293. */
  294. void read_args(int argc, char *argv[])
  295. {
  296. int len;
  297. while (argc >= 2)
  298. {
  299. if (argv[1][0] == '/')
  300. {
  301. len = strlen(&argv[1][1]);
  302. if (argv[1][1] == '?')
  303. usage();
  304. else if (argv[1][1] == '+') /* position */
  305. {
  306. Position = atoi(&argv[1][2]);
  307. if (Position <= 0)
  308. error(MSG_SORT_POSITION);
  309. Position--;
  310. }
  311. else if (_strnicmp(&argv[1][1], "case_sensitive", len) == 0)
  312. Case_sensitive = 1;
  313. else if (_strnicmp(&argv[1][1], "locale", len) == 0) /* locale */
  314. {
  315. if (argc < 3)
  316. error(MSG_SORT_INVALID_SWITCH);
  317. Locale = argv[2];
  318. argv++;
  319. argc--;
  320. }
  321. else if (_strnicmp(&argv[1][1], "memory", len) == 0)
  322. {
  323. /* memory limit */
  324. if (argc < 3)
  325. error(MSG_SORT_INVALID_SWITCH);
  326. User_memory_limit = atoi(argv[2]);
  327. argv++;
  328. argc--;
  329. }
  330. else if (_strnicmp(&argv[1][1], "output", len) == 0)
  331. {
  332. /* output file */
  333. if (Output_name != NULL || argc < 3)
  334. error(MSG_SORT_INVALID_SWITCH);
  335. Output_name = ANSI_TO_TCHAR(argv[2]);
  336. argv++;
  337. argc--;
  338. }
  339. else if (_strnicmp(&argv[1][1], "reverse", len) == 0)
  340. Reverse = 1;
  341. else if (_strnicmp(&argv[1][1], "record_maximum", len) == 0)
  342. {
  343. /* maximum number of characters per record */
  344. if (argc < 3)
  345. error(MSG_SORT_INVALID_SWITCH);
  346. Max_rec_length = atoi(argv[2]);
  347. if (Max_rec_length < 128)
  348. Max_rec_length = 128;
  349. if (Max_rec_length >= 65536)
  350. error(MSG_SORT_MAX_TOO_LARGE);
  351. argv++;
  352. argc--;
  353. }
  354. else if (_strnicmp(&argv[1][1], "temporary", len) == 0)
  355. {
  356. if (Temp_dir != NULL || argc < 3)
  357. error(MSG_SORT_INVALID_SWITCH);
  358. Temp_dir = ANSI_TO_TCHAR(argv[2]);
  359. argv++;
  360. argc--;
  361. }
  362. else if (_strnicmp(&argv[1][1], "uni_output", len) == 0)
  363. {
  364. UnicodeOut=TRUE;
  365. }
  366. else
  367. error(MSG_SORT_INVALID_SWITCH);
  368. }
  369. else
  370. {
  371. if (Input_name != NULL)
  372. error(MSG_SORT_ONE_INPUT);
  373. Input_name = ANSI_TO_TCHAR(argv[1]);
  374. }
  375. argc--;
  376. argv++;
  377. }
  378. }
  379. /* INIT_INPUT_OUTPUT - initialize the input and output files.
  380. */
  381. void init_input_output()
  382. {
  383. int mode;
  384. int i;
  385. /* get input handle and type
  386. */
  387. if (Input_name != NULL)
  388. {
  389. Input_handle = CreateFile(Input_name,
  390. GENERIC_READ,
  391. FILE_SHARE_READ,
  392. NULL,
  393. OPEN_EXISTING,
  394. FILE_ATTRIBUTE_NORMAL,
  395. NULL);
  396. if (Input_handle == INVALID_HANDLE_VALUE)
  397. sys_error(Input_name, 0);
  398. }
  399. else
  400. Input_handle = GetStdHandle(STD_INPUT_HANDLE);
  401. Input_type = GetFileType(Input_handle);
  402. if (Input_type == FILE_TYPE_DISK)
  403. {
  404. unsigned low, high;
  405. low = GetFileSize(Input_handle, &high);
  406. Input_size = ((__int64)high << 32) + low;
  407. Input_read_size = 0; /* will be set it init_mem() */
  408. }
  409. else
  410. {
  411. Input_size = -1;
  412. Input_read_size = 4096; /* use appropriate size for keyboard/pipe */
  413. }
  414. if (Output_name)
  415. {
  416. /* Don't open output file yet. It will be opened for writing and
  417. * truncated after we are done reading the input file. This
  418. * handles the case where the input file and output file are the
  419. * same file.
  420. */
  421. Output_type = FILE_TYPE_DISK;
  422. }
  423. else
  424. {
  425. Output_handle = GetStdHandle(STD_OUTPUT_HANDLE);
  426. /* determine if output file is to disk, pipe, or console
  427. */
  428. Output_type = GetFileType(Output_handle);
  429. if (Output_type == FILE_TYPE_CHAR &&
  430. !GetConsoleMode(Output_handle, &mode))
  431. {
  432. Output_type = FILE_TYPE_DISK;
  433. }
  434. }
  435. for (i = 0; i < MAX_IO; i++)
  436. {
  437. HANDLE hEvent;
  438. hEvent = Read_async[i].over.hEvent = CreateEvent(NULL, 1, 0, NULL);
  439. assert(hEvent != NULL);
  440. hEvent = Write_async[i].over.hEvent = CreateEvent(NULL, 1, 0, NULL);
  441. assert(hEvent != NULL);
  442. }
  443. }
  444. /* SBCS_COMPARE - key comparison routine for records that are internally
  445. * stored as ANSI strings.
  446. */
  447. int
  448. _cdecl SBCS_compare(const void *first, const void *second)
  449. {
  450. int ret_val;
  451. ret_val = _stricoll(&((char **)first)[0][Position],
  452. &((char **)second)[0][Position]);
  453. if (Reverse)
  454. ret_val = -ret_val;
  455. return (ret_val);
  456. }
  457. /* SBCS_CASE_COMPARE - case-sensitive key comparison routine for records
  458. * that are internally stored as ANSI strings.
  459. */
  460. int
  461. _cdecl SBCS_case_compare(const void *first, const void *second)
  462. {
  463. int ret_val;
  464. ret_val = strcoll(&((char **)first)[0][Position],
  465. &((char **)second)[0][Position]);
  466. if (Reverse)
  467. ret_val = -ret_val;
  468. return (ret_val);
  469. }
  470. /* UNICODE_COMPARE - key comparison routine for records that are internally
  471. * stored as Unicode strings.
  472. */
  473. int
  474. _cdecl Unicode_compare(const void *first, const void *second)
  475. {
  476. int ret_val;
  477. ret_val = _wcsicoll(&((wchar_t **)first)[0][Position],
  478. &((wchar_t **)second)[0][Position]);
  479. if (Reverse)
  480. ret_val = -ret_val;
  481. return (ret_val);
  482. }
  483. /* UNICODE_CASE_COMPARE - case-sensitive key comparison routine for records
  484. * that are internally stored as Unicode strings.
  485. */
  486. int
  487. _cdecl Unicode_case_compare(const void *first, const void *second)
  488. {
  489. int ret_val;
  490. ret_val = wcscoll(&((wchar_t **)first)[0][Position],
  491. &((wchar_t **)second)[0][Position]);
  492. if (Reverse)
  493. ret_val = -ret_val;
  494. return (ret_val);
  495. }
  496. /* INIT_MEM - set the initial memory allocation.
  497. */
  498. void init_mem()
  499. {
  500. unsigned size;
  501. unsigned vsize;
  502. int buf_size;
  503. int i;
  504. int rec_buf_size;
  505. int rec_n_ptr_size;
  506. char *new;
  507. MemStat.dwLength = sizeof(MemStat);
  508. GlobalMemoryStatusEx(&MemStat);
  509. GetSystemInfo(&Sys);
  510. /* set the memory limit
  511. */
  512. if (User_memory_limit == 0) /* if not specified by user */
  513. {
  514. UINT_PTR limit = (UINT_PTR) __min(MemStat.ullAvailPhys, MAXUINT_PTR / 4);
  515. /* if input or output is not a file, leave half of the available
  516. * memory for other programs. Otherwise use 90%.
  517. */
  518. if (Input_type != FILE_TYPE_DISK || Output_type != FILE_TYPE_DISK)
  519. limit = (int)(limit * 0.45); /* use 45% of available memory */
  520. else
  521. limit = (int)(limit * 0.9); /* use 90% of available memory */
  522. if (limit > ULONG_MAX) {
  523. //
  524. // Note this app will need lots of changes in order to
  525. // use memory > 4G
  526. //
  527. limit = ULONG_MAX - (Sys.dwPageSize * 2);
  528. }
  529. Memory_limit = (unsigned)ROUND_UP(limit, Sys.dwPageSize);
  530. }
  531. else
  532. {
  533. if (User_memory_limit < MIN_MEMORY_SIZE / 1024)
  534. {
  535. warning(MSG_SORT_MEM_TOO_LOW);
  536. Memory_limit = MIN_MEMORY_SIZE;
  537. }
  538. else if (User_memory_limit > (__min(MemStat.ullAvailPageFile, ULONG_MAX) / 1024))
  539. {
  540. warning(MSG_SORT_MEM_GT_PAGE);
  541. Memory_limit = (unsigned) __min(MemStat.ullAvailPageFile, ULONG_MAX);
  542. }
  543. else
  544. Memory_limit = (unsigned) ROUND_UP((__min(User_memory_limit, ULONG_MAX) * 1024), Sys.dwPageSize);
  545. }
  546. /* if memory limit is below minimum, increase it and hope some physical
  547. * memory is freed up.
  548. */
  549. if (Memory_limit < MIN_MEMORY_SIZE)
  550. Memory_limit = MIN_MEMORY_SIZE;
  551. /* calculate the size of all input and output buffers to be no more
  552. * than 10% of all memory, but no larger than 256k.
  553. */
  554. buf_size = (int)(Memory_limit * 0.1) / (2 * MAX_IO);
  555. buf_size = ROUND_DOWN(buf_size, Sys.dwPageSize);
  556. buf_size = max(buf_size, (int)Sys.dwPageSize);
  557. buf_size = min(buf_size, MAX_XFR_SIZE);
  558. Input_buf_size = Output_buf_size = Temp_buf_size = buf_size;
  559. if (Input_type == FILE_TYPE_DISK)
  560. Input_read_size = Input_buf_size;
  561. GetCPInfo(CP_OEMCP, &CPInfo);
  562. rec_buf_size = Max_rec_length * max(sizeof(wchar_t), CPInfo.MaxCharSize);
  563. rec_buf_size = ROUND_UP(rec_buf_size, Sys.dwPageSize);
  564. /* allocate enough initial record and pointer space to hold two maximum
  565. * length records or 1000 pointers.
  566. */
  567. rec_n_ptr_size = 2 * max(Max_rec_length, 4096) * sizeof(wchar_t) +
  568. 1000 * sizeof(wchar_t *);
  569. rec_n_ptr_size = ROUND_UP(rec_n_ptr_size, Sys.dwPageSize);
  570. vsize = MAX_IO * (Input_buf_size + max(Temp_buf_size, Output_buf_size));
  571. vsize += rec_buf_size + rec_n_ptr_size;
  572. /* if initial memory allocation won't fit in the Memory limit
  573. */
  574. if (vsize > Memory_limit)
  575. {
  576. if (User_memory_limit != 0) /* if specified by user */
  577. {
  578. /* if we didn't already warn the user that their memory size
  579. * is too low, do so.
  580. */
  581. if (User_memory_limit >= MIN_MEMORY_SIZE / 1024)
  582. warning(MSG_SORT_MEM_TOO_LOW);
  583. }
  584. /* increase the memory limit and hope some physical memory is freed up.
  585. */
  586. Memory_limit = vsize;
  587. }
  588. Alloc_begin =
  589. (char *)VirtualAlloc(NULL, Memory_limit, MEM_RESERVE, PAGE_READWRITE);
  590. if (Alloc_begin == NULL)
  591. error(MSG_SORT_NOT_ENOUGH_MEMORY);
  592. /* for i/o buffers, allocate enough virtual memory for the maximum
  593. * buffer space we could need.
  594. */
  595. size = 0;
  596. for (i = 0; i < MAX_IO; i++)
  597. {
  598. Out_buf[i] = Alloc_begin + size;
  599. size += max(Temp_buf_size, Output_buf_size);
  600. }
  601. Rec_buf = Alloc_begin + size;
  602. size += rec_buf_size;
  603. for (i = 0; i < MAX_IO; i++)
  604. {
  605. In_buf[i] = Alloc_begin + size;
  606. size += Input_buf_size;
  607. }
  608. Merge_phase_run_begin = In_buf[0];
  609. Out_buf_size = Temp_buf_size; /* assume two-pass sort for now */
  610. /* Initialize Rec and End_recp to sample the input data.
  611. */
  612. Rec = Next_rec = Alloc_begin + size;
  613. size += rec_n_ptr_size;
  614. End_recp = Short_recp = Last_recp = (char **)(Alloc_begin + size);
  615. assert(size == vsize);
  616. new = VirtualAlloc(Alloc_begin, size, MEM_COMMIT, PAGE_READWRITE);
  617. assert(new == Alloc_begin);
  618. #if 0
  619. fprintf(stderr, "using %d, avail %d, buf_size %d\n",
  620. Memory_limit, MemStat.dwAvailPhys, buf_size);
  621. #endif
  622. }
  623. /* READ_NEXT_INPUT_BUF
  624. */
  625. void read_next_input_buf()
  626. {
  627. int bytes_read;
  628. int ret;
  629. async_t *async;
  630. /* if using unbuffered, overlapped reads
  631. */
  632. if (Input_un_over)
  633. {
  634. while (Reads_issued < Reads_completed + In_max_io &&
  635. Input_scheduled < Input_size)
  636. {
  637. async = &Read_async[Reads_issued % In_max_io];
  638. async->over.Offset = (int)Input_scheduled;
  639. async->over.OffsetHigh = (int)(Input_scheduled >> 32);
  640. async->requested = Input_read_size;
  641. ResetEvent(async->over.hEvent);
  642. ret = ReadFile(Input_handle, In_buf[Reads_issued % In_max_io],
  643. async->requested, &async->completed, &async->over);
  644. if (ret == 0 && GetLastError() != ERROR_IO_PENDING)
  645. sys_error(Input_name, 0);
  646. Input_scheduled += async->requested;
  647. Reads_issued++;
  648. }
  649. if (Reads_completed < Reads_issued)
  650. {
  651. async = &Read_async[Reads_completed % In_max_io];
  652. if (async->completed == 0) /* if read didn't complete instantly */
  653. {
  654. ret = GetOverlappedResult(Input_handle, &async->over,
  655. &async->completed, 1);
  656. if (!ret)
  657. sys_error(Input_name, 0);
  658. }
  659. In_buf_next = In_buf[Reads_completed % In_max_io];
  660. bytes_read = async->completed;
  661. Reads_completed++;
  662. }
  663. else
  664. {
  665. EOF_seen = 1;
  666. return;
  667. }
  668. }
  669. else
  670. {
  671. In_buf_next = In_buf[0];
  672. ret = ReadFile(Input_handle, In_buf_next, Input_read_size,
  673. &bytes_read, NULL);
  674. if (!ret)
  675. {
  676. if (GetLastError() == ERROR_BROKEN_PIPE)
  677. bytes_read = 0;
  678. else
  679. sys_error(Input_name != NULL ?
  680. Input_name : get_string(MSG_SORT_INPUT_FILE), 0);
  681. }
  682. Input_scheduled += bytes_read;
  683. }
  684. In_buf_limit = In_buf_next + bytes_read;
  685. if (bytes_read == 0)
  686. {
  687. EOF_seen = 1;
  688. return;
  689. }
  690. Input_read += bytes_read;
  691. }
  692. /* WRITE_WAIT - wait for the oldest-issued write to complete.
  693. */
  694. void write_wait()
  695. {
  696. int ret;
  697. async_t *async;
  698. if (Phase == INPUT_PHASE) /* if input (sort) phase, we're writing to temp file */
  699. {
  700. async = &Write_async[Writes_completed % MAX_IO];
  701. if (async->completed == 0) /* if write didn't complete instantly */
  702. {
  703. ret = GetOverlappedResult(Temp_handle, &async->over,
  704. &async->completed, 1);
  705. if (!ret || async->completed != async->requested)
  706. sys_error(Temp_name, 0);
  707. }
  708. }
  709. else
  710. {
  711. if (Output_un_over)
  712. {
  713. async = &Write_async[Writes_completed % MAX_IO];
  714. if (async->completed == 0) /* if write didn't complete instantly */
  715. {
  716. ret = GetOverlappedResult(Output_handle, &async->over,
  717. &async->completed, 1);
  718. if (!ret || async->completed != async->requested)
  719. sys_error(Output_name != NULL ?
  720. Output_name : get_string(MSG_SORT_OUTPUT_FILE), 0);
  721. }
  722. }
  723. }
  724. Writes_completed++;
  725. }
  726. /* FLUSH_OUTPUT_BUF - flush the remainder data at the end of the temp or
  727. * output file.
  728. */
  729. void flush_output_buf()
  730. {
  731. int bytes_written;
  732. int ret;
  733. async_t *async;
  734. async = &Write_async[Writes_issued % MAX_IO];
  735. async->over.Offset = (int)Out_offset;
  736. async->over.OffsetHigh = (int)(Out_offset >> 32);
  737. async->requested = Out_buf_bytes;
  738. if (Phase == INPUT_PHASE) /* if input (sort) phase, we're writing to temp file */
  739. {
  740. ResetEvent(async->over.hEvent);
  741. ret = WriteFile(Temp_handle, Out_buf[Writes_issued % MAX_IO],
  742. async->requested, &async->completed, &async->over);
  743. if (ret == 0 && GetLastError() != ERROR_IO_PENDING)
  744. sys_error(Temp_name, 0);
  745. }
  746. else
  747. {
  748. if (Output_un_over)
  749. {
  750. /* if this is the last write and it is not a multiple of
  751. * the sector size.
  752. */
  753. if (Out_buf_bytes % Output_sector_size)
  754. {
  755. /* close handle and reopen it for buffered writes so that
  756. * a non-sector-sized write can be done.
  757. */
  758. CloseHandle(Output_handle);
  759. Output_handle = CreateFile(Output_name,
  760. GENERIC_WRITE,
  761. FILE_SHARE_READ,
  762. NULL,
  763. OPEN_ALWAYS,
  764. FILE_FLAG_OVERLAPPED,
  765. NULL);
  766. if (Output_handle == INVALID_HANDLE_VALUE)
  767. sys_error(Output_name, 0);
  768. }
  769. ResetEvent(async->over.hEvent);
  770. ret = WriteFile(Output_handle, Out_buf[Writes_issued % Out_max_io],
  771. async->requested, &async->completed, &async->over);
  772. if (ret == 0 && GetLastError() != ERROR_IO_PENDING)
  773. sys_error(Output_name != NULL ?
  774. Output_name : get_string(MSG_SORT_OUTPUT_FILE), 0);
  775. }
  776. else
  777. {
  778. ret = WriteFile(Output_handle, Out_buf[Writes_issued % Out_max_io],
  779. Out_buf_bytes, &bytes_written, NULL);
  780. if (!ret || bytes_written != Out_buf_bytes)
  781. sys_error(Output_name != NULL ?
  782. Output_name : get_string(MSG_SORT_OUTPUT_FILE), 0);
  783. async->completed = bytes_written;
  784. }
  785. }
  786. Out_offset += Out_buf_bytes;
  787. Out_buf_bytes = 0;
  788. Writes_issued++;
  789. }
  790. /* TEST_FOR_UNICODE - test if input is Unicode and determine various
  791. * record lenths.
  792. */
  793. void test_for_unicode()
  794. {
  795. read_next_input_buf();
  796. if (Input_read == 0)
  797. EOF_seen = 1;
  798. if (Input_read > 1 && IsTextUnicode(In_buf_next, (int)Input_read, NULL))
  799. {
  800. Input_chars = CHAR_UNICODE;
  801. if (*(wchar_t *)In_buf_next == 0xfeff)
  802. In_buf_next += sizeof(wchar_t); /* eat byte order mark */
  803. Max_rec_bytes_internal = Max_rec_length * sizeof(wchar_t);
  804. Max_rec_bytes_external = Max_rec_length * sizeof(wchar_t);
  805. }
  806. else
  807. {
  808. /* use single-byte mode only if the "C" locale is used. This is
  809. * because _stricoll() is *much* slower than _wcsicoll() if the
  810. * locale is not "C".
  811. */
  812. if (CPInfo.MaxCharSize == 1 && Locale != NULL && !strcmp(Locale, "C"))
  813. {
  814. Input_chars = CHAR_SINGLE_BYTE;
  815. Max_rec_bytes_internal = Max_rec_length;
  816. Max_rec_bytes_external = Max_rec_length;
  817. }
  818. else
  819. {
  820. Input_chars = CHAR_MULTI_BYTE;
  821. Max_rec_bytes_internal = Max_rec_length * sizeof(wchar_t);
  822. Max_rec_bytes_external = Max_rec_length * CPInfo.MaxCharSize;
  823. }
  824. }
  825. Output_chars = Input_chars;
  826. /* Incredible as it might seem, even when the input is Unicode we
  827. * produce multibyte character output. (This follows the previous
  828. * NT sort implementation.) The previous implementation would write
  829. * Unicode directly to the console, but we always translate to
  830. * multibyte characters so we can always use WriteFile(), avoiding
  831. * WriteConsole().
  832. */
  833. if (UnicodeOut) {
  834. Output_chars=CHAR_UNICODE;
  835. } else {
  836. if (Input_chars == CHAR_UNICODE)
  837. Output_chars = CHAR_MULTI_BYTE;
  838. }
  839. /* define the record comparison routine
  840. */
  841. Compare = Input_chars == CHAR_SINGLE_BYTE ?
  842. (Case_sensitive ? SBCS_case_compare : SBCS_compare) :
  843. (Case_sensitive ? Unicode_case_compare : Unicode_compare);
  844. }
  845. /* GET_SECTOR_SIZE - get the sector size of a file.
  846. */
  847. int get_sector_size(TCHAR *path)
  848. {
  849. TCHAR *ptr;
  850. int sector_size;
  851. TCHAR buf[1000];
  852. int foo;
  853. // Initialize to null length string
  854. buf[0] = 0;
  855. // protect against null pointer and buffer overrun
  856. if ( (path != NULL) && (_tcslen(path) < (sizeof(buf)/sizeof(buf[0])) ) ) {
  857. _tcscpy(buf, path);
  858. }
  859. /* attempt to determine the sector size of the temporary device.
  860. * This is complicated by the fact that GetDiskFreeSpace requires
  861. * a root path (why?).
  862. *
  863. * Try transforming the temp directory to its root path. If that doesn't
  864. * work, get the sector size of the current disk.
  865. */
  866. ptr = _tcschr(buf, '\\');
  867. if (ptr != NULL)
  868. ptr[1] = 0; /* transform temp_path to its root directory */
  869. if (!GetDiskFreeSpace(buf, &foo, &sector_size, &foo, &foo))
  870. GetDiskFreeSpace(NULL, &foo, &sector_size, &foo, &foo);
  871. return (sector_size);
  872. }
  873. /* INIT_TWO_PASS - initialize for a two-pass sort.
  874. */
  875. void init_two_pass()
  876. {
  877. TCHAR temp_path[TEMP_LENGTH];
  878. if (Two_pass == 1)
  879. return;
  880. Two_pass = 1;
  881. if (Temp_dir != NULL)
  882. _tcscpy(temp_path, Temp_dir);
  883. else
  884. if ( !GetTempPath(TEMP_LENGTH - 1, temp_path) ) {
  885. sys_error(_TEXT("TEMP path"), 0);
  886. }
  887. GetTempFileName(temp_path, _TEXT("srt"), 0, Temp_name);
  888. Temp_handle =
  889. CreateFile(Temp_name,
  890. GENERIC_READ | GENERIC_WRITE,
  891. 0, /* don't share file access */
  892. NULL,
  893. CREATE_ALWAYS,
  894. FILE_FLAG_NO_BUFFERING |
  895. FILE_FLAG_OVERLAPPED | FILE_FLAG_DELETE_ON_CLOSE,
  896. NULL);
  897. if (Temp_handle == INVALID_HANDLE_VALUE)
  898. sys_error(Temp_name, 0);
  899. Temp_sector_size = get_sector_size(temp_path);
  900. }
  901. /* REVIEW_OUTPUT_MODE - now that we are ready to write to the output file,
  902. * determine how we should write it.
  903. */
  904. void review_output_mode()
  905. {
  906. MEMORYSTATUSEX ms;
  907. CloseHandle(Input_handle);
  908. Out_offset = 0;
  909. Out_buf_size = Output_buf_size;
  910. if (Output_type != FILE_TYPE_DISK)
  911. {
  912. Out_buf_size = min(Out_buf_size, 4096);
  913. return;
  914. }
  915. /* if we are performing a two-pass sort, or there is not enough
  916. * available physical memory to hold the output file.
  917. */
  918. ms.dwLength = sizeof(ms);
  919. GlobalMemoryStatusEx(&ms);
  920. if (Two_pass || (ms.ullAvailPhys < (ULONGLONG)Input_read))
  921. {
  922. if (Output_name == NULL)
  923. {
  924. warning(MSG_SORT_REDIRECT_OUTPUT);
  925. return;
  926. }
  927. Output_un_over = 1;
  928. }
  929. /* if Output_name has been specified, we haven't opened Output_handle
  930. * yet.
  931. */
  932. if (Output_name)
  933. {
  934. if (Output_un_over)
  935. {
  936. Out_max_io = MAX_IO;
  937. Output_sector_size = get_sector_size(Output_name);
  938. Output_handle =
  939. CreateFile(Output_name,
  940. GENERIC_WRITE,
  941. FILE_SHARE_READ,
  942. NULL,
  943. CREATE_ALWAYS,
  944. FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
  945. NULL);
  946. }
  947. else
  948. {
  949. Output_handle =
  950. CreateFile(Output_name,
  951. GENERIC_WRITE,
  952. FILE_SHARE_READ,
  953. NULL,
  954. CREATE_ALWAYS,
  955. FILE_ATTRIBUTE_NORMAL,
  956. NULL);
  957. }
  958. if (Output_handle == INVALID_HANDLE_VALUE)
  959. sys_error(Output_name, 0);
  960. }
  961. }
  962. /* READ_REC - read a record from the input file into main memory,
  963. * translating to Unicode if necessary.
  964. */
  965. void read_rec()
  966. {
  967. char *begin;
  968. char *limit;
  969. char *cp;
  970. wchar_t *wp;
  971. int bsize;
  972. int char_count;
  973. int rec_buf_bytes;
  974. int delimiter_found;
  975. /* if input buffer is empty
  976. */
  977. if (In_buf_next == In_buf_limit)
  978. {
  979. read_next_input_buf();
  980. if (EOF_seen)
  981. return;
  982. }
  983. begin = In_buf_next;
  984. limit = In_buf_limit;
  985. /* loop until we have scanned the next record
  986. *
  987. * when we exit the following loop:
  988. * - "begin" will point to the scanned record (either in the original
  989. * input buffer or in Rec_buf)
  990. * - "bsize" will contain the number of bytes in the record.
  991. */
  992. cp = begin;
  993. delimiter_found = 0;
  994. rec_buf_bytes = 0;
  995. for (;;)
  996. {
  997. /* potentially adjust scan limit because of maximum record length
  998. */
  999. if (limit > cp + Max_rec_bytes_external - rec_buf_bytes)
  1000. limit = cp + Max_rec_bytes_external - rec_buf_bytes;
  1001. if (Input_chars == CHAR_UNICODE)
  1002. {
  1003. wp = (wchar_t *)cp;
  1004. while (wp < (wchar_t *)limit &&
  1005. *wp != '\n' && *wp != '\0' && *wp != CTRL_Z)
  1006. {
  1007. wp++;
  1008. }
  1009. cp = (char *)wp;
  1010. bsize = (int)(cp - begin);
  1011. if (cp == limit) /* didn't find delimiter, ran out of input */
  1012. In_buf_next = (char *)wp;
  1013. else
  1014. {
  1015. delimiter_found = 1;
  1016. In_buf_next = (char *)(wp + 1);
  1017. if (*wp == CTRL_Z)
  1018. {
  1019. EOF_seen = 1;
  1020. if (bsize + rec_buf_bytes == 0)
  1021. return; /* ignore zero sized record */
  1022. }
  1023. }
  1024. }
  1025. else /* single or multi byte input */
  1026. {
  1027. while (cp < limit && *cp != '\n' && *cp != '\0' && *cp != CTRL_Z)
  1028. cp++;
  1029. bsize = (int)(cp - begin);
  1030. if (cp == limit) /* didn't find delimiter, ran out of input */
  1031. In_buf_next = cp;
  1032. else
  1033. {
  1034. delimiter_found = 1;
  1035. In_buf_next = cp + 1;
  1036. if (*cp == CTRL_Z)
  1037. {
  1038. EOF_seen = 1;
  1039. if (bsize + rec_buf_bytes == 0)
  1040. return; /* ignore zero sized record */
  1041. }
  1042. }
  1043. }
  1044. /* if we didn't find the delimiter or we have already stored
  1045. * the beginning portion of the record in Rec_buf.
  1046. */
  1047. if (!delimiter_found || rec_buf_bytes)
  1048. {
  1049. /* copy the portion of the record into Rec_buf
  1050. */
  1051. if (rec_buf_bytes + bsize >= Max_rec_bytes_external)
  1052. error(MSG_SORT_REC_TOO_BIG);
  1053. memcpy((char *)Rec_buf + rec_buf_bytes, begin, bsize);
  1054. rec_buf_bytes += bsize;
  1055. if (!delimiter_found)
  1056. {
  1057. /* read another input buffer
  1058. */
  1059. read_next_input_buf();
  1060. if (!EOF_seen)
  1061. {
  1062. cp = begin = In_buf_next;
  1063. limit = In_buf_limit;
  1064. continue; /* scan some more to find record delimiter */
  1065. }
  1066. /* EOF reached without finding delimiter. Fall through
  1067. * and use whatever we have in Rec_buf as the record. */
  1068. }
  1069. /* set begin and size of record in Rec_buf
  1070. */
  1071. begin = Rec_buf;
  1072. bsize = rec_buf_bytes;
  1073. break;
  1074. }
  1075. else /* found delimiter && haven't store a record prefix in Rec_buf */
  1076. break;
  1077. }
  1078. /* ignore any carriage return at end of record
  1079. */
  1080. if (Input_chars == CHAR_UNICODE)
  1081. {
  1082. wp = (wchar_t *)(begin + bsize);
  1083. if (bsize && wp[-1] == '\r')
  1084. bsize -= sizeof(wchar_t);
  1085. }
  1086. else
  1087. {
  1088. cp = begin + bsize;
  1089. if (bsize && cp[-1] == '\r')
  1090. bsize -= 1;
  1091. }
  1092. /* copy scanned record into internal storage
  1093. */
  1094. cp = Next_rec;
  1095. if (Input_chars == CHAR_SINGLE_BYTE)
  1096. {
  1097. memcpy(Next_rec, begin, bsize);
  1098. char_count = bsize;
  1099. cp[char_count] = 0;
  1100. Next_rec += char_count + 1;
  1101. }
  1102. else
  1103. {
  1104. if (Input_chars == CHAR_UNICODE)
  1105. {
  1106. memcpy(Next_rec, begin, bsize);
  1107. char_count = bsize / sizeof(wchar_t);
  1108. }
  1109. else /* CHAR_MULTI_BYTE */
  1110. {
  1111. if (bsize)
  1112. {
  1113. char_count = MultiByteToWideChar(CP_OEMCP, 0,
  1114. begin, bsize,
  1115. (wchar_t *)Next_rec,
  1116. Max_rec_length);
  1117. if (char_count == 0)
  1118. error(MSG_SORT_REC_TOO_BIG);
  1119. }
  1120. else
  1121. char_count = 0;
  1122. }
  1123. wp = (wchar_t *)Next_rec;
  1124. wp[char_count] = 0;
  1125. Next_rec = (char *)(wp + char_count + 1);
  1126. }
  1127. /* store pointer to record
  1128. *
  1129. * if record is short (the /+n option directs us to skip to the
  1130. * delimiting NULL in the record or beyond), place record in a
  1131. * separate "short" list.
  1132. */
  1133. if (char_count <= Position)
  1134. {
  1135. --Last_recp;
  1136. --Short_recp;
  1137. *Last_recp = *Short_recp;
  1138. *Short_recp = cp;
  1139. }
  1140. else
  1141. *--Last_recp = cp; /* place record in list of normal records */
  1142. }
  1143. /* MERGE_PHASE_RUNS_ALLOWED - determine the number of runs allowed for
  1144. * the given memory and temp buf size.
  1145. */
  1146. unsigned merge_phase_runs_allowed(unsigned mem_size, int temp_buf_size)
  1147. {
  1148. unsigned overhead;
  1149. unsigned bytes_per_run;
  1150. /* per run memory consists of temp file buffers, record buffer,
  1151. * run struct and tournament tree pointer.
  1152. */
  1153. bytes_per_run = temp_buf_size * N_RUN_BUFS +
  1154. Max_rec_bytes_internal + sizeof(run_t) + sizeof(run_t *);
  1155. overhead = (unsigned)(Merge_phase_run_begin - Alloc_begin);
  1156. return ((mem_size - overhead) / bytes_per_run);
  1157. }
  1158. /* TWO_PASS_FIT - determine if the sort will fit in two passes.
  1159. */
  1160. BOOL two_pass_fit(__int64 internal_size, unsigned mem_size, int temp_buf_sz)
  1161. {
  1162. unsigned temp;
  1163. __int64 est_runs;
  1164. unsigned mpra;
  1165. unsigned sort_phase_overhead;
  1166. sort_phase_overhead =
  1167. (unsigned)((Rec - Alloc_begin) + Max_rec_bytes_internal + sizeof(char *));
  1168. mpra = merge_phase_runs_allowed(mem_size, temp_buf_sz);
  1169. /* estimate the number of runs that would be produced during the
  1170. * sort phase by the given memory size. Assume we will leave
  1171. * space for twice the allowed runs. If the number of runs is
  1172. * larger than expected, we will reduce the Temp_buf_size to
  1173. * allow them to fit in the merge phase.
  1174. */
  1175. Run_limit = 2 * mpra;
  1176. temp = mem_size - (sort_phase_overhead +
  1177. Run_limit * (sizeof(run_t) + sizeof(run_t *)));
  1178. est_runs = (internal_size + temp - 1) / temp;
  1179. /* mem_size allows a fit if the number of runs produced by the
  1180. * sort phase is <= the number of runs that fit in memory
  1181. * during the merge phase.
  1182. */
  1183. return (est_runs <= mpra);
  1184. }
  1185. /* FIND_TWO_PASS_MEMORY_SIZE - find the memory size such that a two-pass
  1186. * sort can be performed.
  1187. */
  1188. unsigned find_two_pass_mem_size(__int64 internal_size)
  1189. {
  1190. unsigned curr_size;
  1191. unsigned last_size;
  1192. unsigned lower_limit;
  1193. unsigned upper_limit;
  1194. unsigned temp_rd_sz;
  1195. /* if a two-pass sort can be performed with the current Temp_buf_size.
  1196. */
  1197. if (two_pass_fit(internal_size, Memory_limit, Temp_buf_size))
  1198. {
  1199. /* perform a binary search to find the minimum memory size for
  1200. * a two-pass sort with the current Temp_buf_size.
  1201. * This will even out the memory usage between the sort phase
  1202. * and merge phase.
  1203. */
  1204. lower_limit = (unsigned)((char *)End_recp - Alloc_begin); /* existing size */
  1205. upper_limit = Memory_limit;
  1206. curr_size = ROUND_UP((lower_limit + upper_limit) / 2, Sys.dwPageSize);
  1207. do
  1208. {
  1209. last_size = curr_size;
  1210. if (two_pass_fit(internal_size, curr_size, Temp_buf_size))
  1211. {
  1212. upper_limit = curr_size;
  1213. curr_size = (curr_size + lower_limit) / 2;
  1214. }
  1215. else
  1216. {
  1217. lower_limit = curr_size;
  1218. curr_size = (curr_size + upper_limit) / 2;
  1219. }
  1220. curr_size = ROUND_UP(curr_size, Sys.dwPageSize);
  1221. } while (curr_size != last_size);
  1222. return (curr_size);
  1223. }
  1224. else
  1225. {
  1226. /* keep reducing theoretical temp file read size until it fits.
  1227. * This iteration is an exercise directed at getting a
  1228. * reasonable (not too large) Run_limit. The actual temp file
  1229. * read size will not be set until the beginning of the merge phase.
  1230. */
  1231. for (temp_rd_sz = Temp_buf_size - Sys.dwPageSize;
  1232. temp_rd_sz >= Sys.dwPageSize; temp_rd_sz -= Sys.dwPageSize)
  1233. {
  1234. if (two_pass_fit(internal_size, Memory_limit, temp_rd_sz))
  1235. break;
  1236. }
  1237. /* if it didn't even fit with the mimium temp buf read size, give up.
  1238. */
  1239. if (temp_rd_sz < Sys.dwPageSize)
  1240. error(MSG_SORT_NOT_ENOUGH_MEMORY);
  1241. return (Memory_limit);
  1242. }
  1243. }
  1244. /* STRATEGY - determine if we have sufficent memory for a one-pass sort,
  1245. * or if we should optimize for a two-pass sort.
  1246. */
  1247. void strategy()
  1248. {
  1249. int ptr_bytes;
  1250. int delta;
  1251. unsigned new_size;
  1252. int n_recs;
  1253. int n_internal_bytes;
  1254. int bytes_read;
  1255. __int64 est_internal_size;
  1256. __int64 est_one_pass_size;
  1257. /* determine appropriate memory size to use
  1258. */
  1259. if (Input_type != FILE_TYPE_DISK)
  1260. {
  1261. /* Don't know the size of the input. Allocate as much memory
  1262. * as possible and hope it fits in either one or two passes.
  1263. */
  1264. new_size = Memory_limit;
  1265. Run_limit = merge_phase_runs_allowed(new_size, Sys.dwPageSize);
  1266. }
  1267. else
  1268. {
  1269. n_recs = (int)(End_recp - Last_recp);
  1270. n_internal_bytes = (int)(Next_rec - Rec);
  1271. bytes_read = (int)Input_read - (int)(In_buf_limit - In_buf_next);
  1272. /* estimate the amount of internal memory it would take to
  1273. * hold the entire input file.
  1274. */
  1275. est_internal_size = (__int64)
  1276. (((double)(n_internal_bytes + n_recs * sizeof(char *)) / bytes_read)
  1277. * Input_size);
  1278. /* calculate the total estimated amount of main memory for a one
  1279. * pass sort. Since smaller record sizes than those already sampled
  1280. * can require additional memory (more ptrs per record byte), we will
  1281. * bump up the estimated record and pointer size by 10%.
  1282. */
  1283. est_one_pass_size = (__int64)
  1284. ((double)est_internal_size * 1.1 +
  1285. (Rec - Alloc_begin) + Max_rec_bytes_internal + sizeof(char *));
  1286. est_one_pass_size = ROUND_UP(est_one_pass_size, Sys.dwPageSize);
  1287. if (User_memory_limit)
  1288. {
  1289. new_size = Memory_limit; /* da user's da boss */
  1290. Run_limit = merge_phase_runs_allowed(new_size, Sys.dwPageSize);
  1291. }
  1292. else if (est_one_pass_size <= Memory_limit)
  1293. {
  1294. new_size = (int)est_one_pass_size; /* plan for one pass sort */
  1295. Run_limit = 2; /* just in case we don't make it */
  1296. }
  1297. else
  1298. {
  1299. /* find memory size for a two-pass sort
  1300. */
  1301. new_size = find_two_pass_mem_size(est_internal_size);
  1302. init_two_pass();
  1303. }
  1304. /* if input file and sort memory will not fit in available memory,
  1305. * access input file as unbuffered and overlapped.
  1306. */
  1307. if (Input_size + est_one_pass_size > Memory_limit)
  1308. {
  1309. if (Input_name == NULL)
  1310. warning(MSG_SORT_REDIRECT_INPUT);
  1311. else
  1312. {
  1313. /* close input file handle,
  1314. * reopen it handle as unbuffered and overlapped.
  1315. */
  1316. CloseHandle(Input_handle);
  1317. Input_handle =
  1318. CreateFile(Input_name,
  1319. GENERIC_READ,
  1320. FILE_SHARE_READ,
  1321. NULL,
  1322. OPEN_EXISTING,
  1323. FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
  1324. NULL);
  1325. if (Input_handle == INVALID_HANDLE_VALUE)
  1326. sys_error(Input_name, 0);
  1327. Input_un_over = 1;
  1328. In_max_io = MAX_IO;
  1329. }
  1330. }
  1331. }
  1332. #if 0
  1333. fprintf(stderr, "new_size: %d\n", new_size);
  1334. #endif
  1335. assert(new_size > (unsigned)((char *)End_recp - Alloc_begin));
  1336. if (VirtualAlloc(Alloc_begin, new_size, MEM_COMMIT, PAGE_READWRITE)
  1337. == NULL)
  1338. {
  1339. error(MSG_SORT_NOT_ENOUGH_MEMORY);
  1340. }
  1341. /* allocate the run array and tournament tree backwards from the end
  1342. * of the newly allocated memory.
  1343. */
  1344. Tree = (run_t **)(Alloc_begin + new_size - Run_limit * sizeof(run_t *));
  1345. Run = (run_t *)((char *)Tree - Run_limit * sizeof(run_t));
  1346. /* reallocate record pointers to end of the enlarged memory block.
  1347. */
  1348. delta = (int)((char **)Run - End_recp);
  1349. ptr_bytes = (int)((char *)End_recp - (char *)Last_recp);
  1350. memcpy(Last_recp + delta, Last_recp, ptr_bytes);
  1351. Last_recp += delta;
  1352. Short_recp += delta;
  1353. End_recp += delta;
  1354. }
  1355. /* READ_INPUT - read records from the input file until there is not enough
  1356. * space for a maximum-length record.
  1357. */
  1358. void read_input()
  1359. {
  1360. /* While there is space for a maximum-length record and its pointer
  1361. */
  1362. while (!EOF_seen && (char *)(Last_recp - 1) - Next_rec >=
  1363. Max_rec_bytes_internal + (int)sizeof(char *))
  1364. {
  1365. read_rec();
  1366. }
  1367. }
  1368. /* SAMPLE_INPUT - read some records into the initial memory allocation
  1369. * so we can later analyze the records.
  1370. */
  1371. void sample_input()
  1372. {
  1373. /* read some input and test for unicode
  1374. */
  1375. test_for_unicode();
  1376. /* Read records into the initially small memory allocation so that
  1377. * we can calculate average record lengths.
  1378. */
  1379. if (!EOF_seen)
  1380. read_input();
  1381. }
  1382. /* SORT - sort the "normal" length records in main memory.
  1383. */
  1384. void sort()
  1385. {
  1386. qsort(Last_recp, (unsigned)(Short_recp - Last_recp), sizeof(void *), Compare);
  1387. }
  1388. /* OUTPUT_REC - output a record to either the temporary or output file.
  1389. */
  1390. void output_rec(char *cp)
  1391. {
  1392. int buf_bytes;
  1393. int copy_size;
  1394. int bsize;
  1395. char *rec;
  1396. /* copy/transform record bytes into Rec_buf
  1397. */
  1398. rec = Rec_buf;
  1399. if (Output_chars == CHAR_UNICODE)
  1400. {
  1401. bsize = wcslen((wchar_t *)cp) * sizeof(wchar_t);
  1402. memcpy(rec, cp, bsize);
  1403. if (Phase == INPUT_PHASE) /* if input phase and writing to temp disks */
  1404. {
  1405. *(wchar_t *)(rec + bsize) = L'\0';
  1406. bsize += sizeof(wchar_t);
  1407. }
  1408. else
  1409. {
  1410. *(wchar_t *)(rec + bsize) = L'\r';
  1411. bsize += sizeof(wchar_t);
  1412. *(wchar_t *)(rec + bsize) = L'\n';
  1413. bsize += sizeof(wchar_t);
  1414. }
  1415. }
  1416. else
  1417. {
  1418. if (Output_chars == CHAR_MULTI_BYTE)
  1419. {
  1420. bsize = WideCharToMultiByte(CP_OEMCP, 0,
  1421. (wchar_t *)cp, -1,
  1422. rec, Max_rec_bytes_external,
  1423. NULL, NULL);
  1424. assert(bsize != 0);
  1425. bsize--; /* ignore trailing zero */
  1426. }
  1427. else /* Output_chars == CHAR_SINGLE_BYTE */
  1428. {
  1429. bsize = strlen(cp);
  1430. memcpy(rec, cp, bsize);
  1431. }
  1432. if (Phase == INPUT_PHASE) /* if input phase and writing to temp disks */
  1433. rec[bsize++] = '\0';
  1434. else
  1435. {
  1436. rec[bsize++] = '\r';
  1437. rec[bsize++] = '\n';
  1438. }
  1439. }
  1440. /* copy record bytes to output buffer and initiate a write, if necessary
  1441. */
  1442. buf_bytes = Out_buf_bytes;
  1443. for (;;)
  1444. {
  1445. copy_size = min(bsize, Out_buf_size - buf_bytes);
  1446. memcpy(Out_buf[Writes_issued % (Phase == INPUT_PHASE ? MAX_IO : Out_max_io)]
  1447. + buf_bytes, rec, copy_size);
  1448. buf_bytes += copy_size;
  1449. if (buf_bytes < Out_buf_size)
  1450. break;
  1451. Out_buf_bytes = buf_bytes;
  1452. /* if all write buffers have a write pending */
  1453. if (Writes_completed + Out_max_io == Writes_issued)
  1454. write_wait();
  1455. flush_output_buf();
  1456. buf_bytes = 0;
  1457. bsize -= copy_size;
  1458. if (bsize == 0)
  1459. break;
  1460. rec += copy_size;
  1461. }
  1462. Out_buf_bytes = buf_bytes;
  1463. }
  1464. /* OUTPUT_NORMAL - output records whose length is greater than the
  1465. * starting compare Position.
  1466. */
  1467. void output_normal()
  1468. {
  1469. int i, n;
  1470. n = (int)(Short_recp - Last_recp);
  1471. for (i = 0; i < n; i++)
  1472. output_rec(Last_recp[i]);
  1473. }
  1474. /* OUTPUT_SHORTS - output records whose length is equal to or less than the
  1475. * starting compare Position.
  1476. */
  1477. void output_shorts()
  1478. {
  1479. int i, n;
  1480. n = (int)(End_recp - Short_recp);
  1481. for (i = 0; i < n; i++)
  1482. output_rec(Short_recp[i]);
  1483. }
  1484. /* COMPLETE_WRITES - finish the writing of the temp or output file.
  1485. */
  1486. void complete_writes()
  1487. {
  1488. /* wait for all pending writes to complete
  1489. */
  1490. while (Writes_completed != Writes_issued)
  1491. write_wait();
  1492. /* if necessary, issue one last write (possibly unbuffered).
  1493. */
  1494. if (Out_buf_bytes)
  1495. {
  1496. flush_output_buf();
  1497. write_wait();
  1498. }
  1499. }
  1500. /* WRITE_RECS - write out the records which have been read from the input
  1501. * file into main memory, divided into "short" and "normal"
  1502. * records, and sorted.
  1503. *
  1504. * This routine is called to either write a run of records to
  1505. * the temporary file during a two-pass sort (Phase == INPUT_PHASE),
  1506. * or to write all the records to the output file during a
  1507. * one-pass sort.
  1508. */
  1509. void write_recs()
  1510. {
  1511. if (Phase == INPUT_PHASE) /* if writing a run to the temp file */
  1512. {
  1513. if (N_runs == Run_limit)
  1514. error(MSG_SORT_NOT_ENOUGH_MEMORY);
  1515. Run[N_runs].begin_off = Out_offset + Out_buf_bytes;
  1516. }
  1517. if (Reverse)
  1518. output_normal(); /* non-short records go first */
  1519. else
  1520. output_shorts(); /* short records go first */
  1521. if (Phase == INPUT_PHASE) /* if writing a run to the temp file */
  1522. Run[N_runs].mid_off = Out_offset + Out_buf_bytes;
  1523. if (Reverse)
  1524. output_shorts(); /* short records go last */
  1525. else
  1526. output_normal(); /* non-short records go last */
  1527. if (Phase == INPUT_PHASE) /* if writing a run to the temp file */
  1528. {
  1529. int sector_offset;
  1530. Run[N_runs].end_off = Out_offset + Out_buf_bytes;
  1531. /* if not on sector boundry, get on one
  1532. */
  1533. sector_offset = Out_buf_bytes & (Temp_sector_size - 1);
  1534. if (sector_offset)
  1535. memset(Out_buf[Writes_issued % MAX_IO] + Out_buf_bytes, 0,
  1536. Temp_sector_size - sector_offset);
  1537. Out_buf_bytes += Temp_sector_size - sector_offset;
  1538. N_runs++;
  1539. }
  1540. complete_writes();
  1541. }
  1542. /* SCHED_RUN_READ - schedule the next temp file read for the given run.
  1543. */
  1544. void sched_run_read(run_t *run)
  1545. {
  1546. __int64 buf_off;
  1547. int rem;
  1548. int transfer;
  1549. int ret;
  1550. async_t *async;
  1551. buf_off = run->begin_off + run->blks_read * Temp_buf_size;
  1552. transfer = Temp_buf_size;
  1553. if (transfer > run->end_off - buf_off)
  1554. {
  1555. transfer = (int)(run->end_off - buf_off);
  1556. rem = transfer & (Temp_sector_size - 1);
  1557. if (rem)
  1558. transfer += Temp_sector_size - rem;
  1559. }
  1560. async = &Read_async[Reads_issued % MAX_IO];
  1561. async->over.Offset = (int)buf_off;
  1562. async->over.OffsetHigh = (int)(buf_off >> 32);
  1563. async->requested = transfer;
  1564. ResetEvent(async->over.hEvent);
  1565. ret = ReadFile(Temp_handle, run->buf[run->blks_read % N_RUN_BUFS],
  1566. async->requested, &async->completed, &async->over);
  1567. if (ret == 0 && GetLastError() != ERROR_IO_PENDING)
  1568. sys_error(Temp_name, 0);
  1569. Reads_issued++;
  1570. }
  1571. /* QUEUE_RUN_READ - put given run on queue of runs needing their next
  1572. * temp file block read.
  1573. */
  1574. void queue_run_read(run_t *run)
  1575. {
  1576. /* place run on read queue
  1577. */
  1578. run->next = NULL;
  1579. if (Run_read_head == NULL)
  1580. Run_read_head = Run_read_tail = run;
  1581. else
  1582. {
  1583. Run_read_tail->next = run;
  1584. Run_read_tail = run;
  1585. }
  1586. /* if we can schedule a read immediately, do so.
  1587. */
  1588. if (Reads_issued < Reads_completed + MAX_IO)
  1589. sched_run_read(run);
  1590. }
  1591. /* WAIT_BLK_READ - wait for the oldest-issued temp file block read to complete.
  1592. */
  1593. void wait_blk_read()
  1594. {
  1595. assert(Reads_issued != Reads_completed);
  1596. WaitForSingleObject(Read_async[Reads_completed % MAX_IO].over.hEvent,
  1597. INFINITE);
  1598. }
  1599. /* CHECK_RUN_READS - check the temp file reads to see if there are any
  1600. * have finished or need to be started.
  1601. */
  1602. void check_run_reads()
  1603. {
  1604. __int64 buf_off;
  1605. async_t *async;
  1606. run_t *run;
  1607. int ret;
  1608. int i;
  1609. int bytes_read;
  1610. if (Reads_issued == Reads_completed) /* if nothing happening */
  1611. return;
  1612. /* see if most recently issued read has completed
  1613. */
  1614. run = Run_read_head;
  1615. async = &Read_async[Reads_completed % MAX_IO];
  1616. if (async->completed == 0) /* if read didn't complete instantly */
  1617. {
  1618. ret = GetOverlappedResult(Temp_handle, &async->over, &bytes_read, 0);
  1619. if (!ret)
  1620. {
  1621. if (GetLastError() != ERROR_IO_INCOMPLETE)
  1622. sys_error(Temp_name, 0);
  1623. return; /* try again */
  1624. }
  1625. async->completed = bytes_read;
  1626. }
  1627. /* process completed read
  1628. */
  1629. assert(async->completed == async->requested);
  1630. buf_off = (unsigned)async->over.Offset;
  1631. buf_off += (__int64)async->over.OffsetHigh << 32;
  1632. assert(buf_off == run->begin_off + run->blks_read * Temp_buf_size);
  1633. Reads_completed++;
  1634. run->blks_read++;
  1635. Run_read_head = run->next;
  1636. /* Since we just finished a read, we can schedule a new read if there
  1637. * is an unscheduled run on the run read queue.
  1638. */
  1639. run = Run_read_head;
  1640. for (i = Reads_completed; i < Reads_issued; i++)
  1641. run = run->next; /* skip over runs with an issued/scheduled read */
  1642. if (run != NULL)
  1643. sched_run_read(run);
  1644. }
  1645. /* GET_NEXT_TEMP_BUF - get the next buffer of temp file data for the given run.
  1646. */
  1647. void get_next_temp_buf(run_t *run)
  1648. {
  1649. assert(run->next_byte == run->buf_begin + run->buf_bytes);
  1650. /* while the next read for this run has not completed
  1651. */
  1652. while (run->blks_read == run->blks_scanned)
  1653. {
  1654. wait_blk_read();
  1655. check_run_reads();
  1656. }
  1657. run->buf_off = run->begin_off + run->blks_scanned * Temp_buf_size;
  1658. run->buf_begin = run->buf[run->blks_scanned % N_RUN_BUFS];
  1659. run->next_byte = run->buf_begin;
  1660. run->buf_bytes = Temp_buf_size;
  1661. if (run->buf_bytes > run->end_off - run->buf_off)
  1662. run->buf_bytes = (int)(run->end_off - run->buf_off);
  1663. run->blks_scanned++;
  1664. assert(run->blks_scanned <= run->blks_read);
  1665. /* if there is another block to be read for this run, queue it up.
  1666. */
  1667. if (run->begin_off + run->blks_read * Temp_buf_size < run->end_off)
  1668. queue_run_read(run);
  1669. }
  1670. /* READ_TEMP_REC - read the next record from the temporary file for the
  1671. * given run.
  1672. */
  1673. int read_temp_rec(run_t *run)
  1674. {
  1675. char *begin;
  1676. char *limit;
  1677. char *cp;
  1678. wchar_t *wp;
  1679. int bsize;
  1680. int char_count;
  1681. int rec_buf_bytes;
  1682. int delimiter_found;
  1683. /* if the current read offset is up to the end offset, return false.
  1684. */
  1685. if (run->buf_off + (run->next_byte - run->buf_begin) >= run->end_read_off)
  1686. return (0);
  1687. /* if input buffer is empty
  1688. */
  1689. if (run->next_byte == run->buf_begin + run->buf_bytes)
  1690. get_next_temp_buf(run);
  1691. begin = run->next_byte;
  1692. limit = run->buf_begin + run->buf_bytes;
  1693. /* loop until we have scanned the next record
  1694. *
  1695. * when we exit the following loop:
  1696. * - "begin" will point to the scanned record (either in the original
  1697. * input buffer or in Rec_buf)
  1698. * - "bsize" will contain the number of bytes in the record.
  1699. */
  1700. cp = begin;
  1701. delimiter_found = 0;
  1702. rec_buf_bytes = 0;
  1703. for (;;)
  1704. {
  1705. /* potentially adjust scan limit because of maximum record length
  1706. */
  1707. if (limit > cp + Max_rec_bytes_external - rec_buf_bytes)
  1708. limit = cp + Max_rec_bytes_external - rec_buf_bytes;
  1709. if (Input_chars == CHAR_UNICODE)
  1710. {
  1711. wp = (wchar_t *)cp;
  1712. while (wp < (wchar_t *)limit && *wp != '\0')
  1713. {
  1714. wp++;
  1715. }
  1716. cp = (char *)wp;
  1717. bsize = (int)(cp - begin);
  1718. if (cp == limit) /* didn't find delimiter, ran out of input */
  1719. run->next_byte = (char *)wp;
  1720. else
  1721. {
  1722. delimiter_found = 1;
  1723. run->next_byte = (char *)(wp + 1);
  1724. }
  1725. }
  1726. else /* single or multi byte input */
  1727. {
  1728. while (cp < limit && *cp != '\0')
  1729. cp++;
  1730. bsize = (int)(cp - begin);
  1731. if (cp == limit) /* didn't find delimiter, ran out of input */
  1732. run->next_byte = cp;
  1733. else
  1734. {
  1735. delimiter_found = 1;
  1736. run->next_byte = cp + 1;
  1737. }
  1738. }
  1739. /* if we didn't find the delimiter or we have already stored
  1740. * the beginning portion of the record in Rec_buf.
  1741. */
  1742. if (!delimiter_found || rec_buf_bytes)
  1743. {
  1744. /* copy the portion of the record into Rec_buf
  1745. */
  1746. if (rec_buf_bytes + bsize >= Max_rec_bytes_external)
  1747. error(MSG_SORT_REC_TOO_BIG);
  1748. memcpy((char *)Rec_buf + rec_buf_bytes, begin, bsize);
  1749. rec_buf_bytes += bsize;
  1750. if (!delimiter_found)
  1751. {
  1752. /* read another input buffer
  1753. */
  1754. get_next_temp_buf(run);
  1755. cp = begin = run->next_byte;
  1756. limit = run->buf_begin + run->buf_bytes;
  1757. continue; /* scan some more to find record delimiter */
  1758. }
  1759. /* set begin and size of record in Rec_buf
  1760. */
  1761. begin = Rec_buf;
  1762. bsize = rec_buf_bytes;
  1763. break;
  1764. }
  1765. else /* found delimiter && haven't store a record prefix in Rec_buf */
  1766. break;
  1767. }
  1768. /* copy scanned record into internal storage
  1769. */
  1770. cp = run->rec;
  1771. if (Input_chars == CHAR_SINGLE_BYTE)
  1772. {
  1773. memcpy(run->rec, begin, bsize);
  1774. char_count = bsize;
  1775. cp[char_count] = 0;
  1776. }
  1777. else
  1778. {
  1779. if (Input_chars == CHAR_UNICODE)
  1780. {
  1781. memcpy(run->rec, begin, bsize);
  1782. char_count = bsize / sizeof(wchar_t);
  1783. }
  1784. else /* CHAR_MULTI_BYTE */
  1785. {
  1786. if (bsize)
  1787. {
  1788. char_count = MultiByteToWideChar(CP_OEMCP, 0,
  1789. begin, bsize,
  1790. (wchar_t *)run->rec,
  1791. Max_rec_length);
  1792. if (char_count == 0)
  1793. error(MSG_SORT_CHAR_CONVERSION);
  1794. }
  1795. }
  1796. wp = (wchar_t *)run->rec;
  1797. wp[char_count] = 0;
  1798. }
  1799. return (1);
  1800. }
  1801. /* COPY_SHORTS - copy the "short" records for each run to the output file.
  1802. */
  1803. void copy_shorts()
  1804. {
  1805. unsigned int i;
  1806. run_t *run;
  1807. for (i = 0; i < N_runs; i++)
  1808. {
  1809. run = &Run[i];
  1810. while (read_temp_rec(run))
  1811. output_rec(run->rec);
  1812. }
  1813. }
  1814. /* TREE_INSERT - insert a next record for the given run into the
  1815. * tournament tree.
  1816. */
  1817. run_t *tree_insert(run_t *run, int not_empty)
  1818. {
  1819. int i;
  1820. run_t **node;
  1821. run_t *winner;
  1822. run_t *temp;
  1823. int (_cdecl *compare)(const void *, const void *);
  1824. compare = Compare;
  1825. winner = (not_empty ? run : END_OF_RUN);
  1826. /* start at the bottom of the tournament tree, work up the the top
  1827. * comparing the current winner run with the runs on the path to the
  1828. * top of the tournament tree.
  1829. */
  1830. for (i = (run->index + N_runs) / 2; i != 0; i >>= 1)
  1831. {
  1832. node = &Tree[i];
  1833. /* empty tree nodes get filled immediately, and we're done with the
  1834. * insertion as all node above this one must be empty also.
  1835. */
  1836. if (*node == NULL_RUN)
  1837. {
  1838. *node = winner;
  1839. return (NULL_RUN);
  1840. }
  1841. /* if run at current tree node has reached its end, it loses (no swap).
  1842. */
  1843. if (*node == END_OF_RUN)
  1844. continue;
  1845. else if (winner == END_OF_RUN)
  1846. {
  1847. /* current winner run has reached the end of its records,
  1848. * swap and contine.
  1849. */
  1850. winner = *node;
  1851. *node = END_OF_RUN;
  1852. }
  1853. else
  1854. {
  1855. /* both the winner run and the run at the current node have
  1856. * a record. Compare records and swap run pointer if necessary.
  1857. */
  1858. if (compare((void *)&winner->rec, (void *)&(*node)->rec) > 0)
  1859. {
  1860. temp = winner;
  1861. winner = *node;
  1862. *node = temp;
  1863. }
  1864. }
  1865. }
  1866. return (winner);
  1867. }
  1868. /* MERGE_RUNS - merge the runs in the temporary file to produce a stream of
  1869. * "normal"-length records to be written to the output file.
  1870. */
  1871. void merge_runs()
  1872. {
  1873. unsigned int i;
  1874. run_t *run;
  1875. /* initialize all tree nodes to be empty
  1876. */
  1877. for (i = 0; i < N_runs; i++)
  1878. Tree[i] = NULL_RUN;
  1879. /* fill tree with all runs except for the first
  1880. */
  1881. for (i = 1; i < N_runs; i++)
  1882. {
  1883. run = &Run[i];
  1884. run = tree_insert(run, read_temp_rec(run));
  1885. assert(run == NULL_RUN);
  1886. }
  1887. /* replacement-selection main loop
  1888. */
  1889. run = &Run[0];
  1890. for (i = 0; ; i++)
  1891. {
  1892. /* replace winner record by inserting next record from the same
  1893. * run into the tournament tree.
  1894. */
  1895. run = tree_insert(run, read_temp_rec(run));
  1896. if ( (run == END_OF_RUN) ||
  1897. (run == NULL_RUN) )
  1898. {
  1899. break;
  1900. }
  1901. output_rec(run->rec); /* output winner record */
  1902. if ((i & 0xff) == 0)
  1903. check_run_reads(); /* periodically check run reads */
  1904. }
  1905. }
  1906. /* MERGE_PASS - execute the merge pass of a two-pass sort.
  1907. */
  1908. void merge_pass()
  1909. {
  1910. unsigned int i, j;
  1911. int per_run_mem;
  1912. int read_buf_size;
  1913. per_run_mem = (int)(((char *)Run - Merge_phase_run_begin) / N_runs);
  1914. read_buf_size = (per_run_mem - Max_rec_bytes_internal) / N_RUN_BUFS;
  1915. read_buf_size = ROUND_DOWN(read_buf_size, Sys.dwPageSize);
  1916. if (read_buf_size == 0)
  1917. error(MSG_SORT_NOT_ENOUGH_MEMORY);
  1918. if (read_buf_size > MAX_XFR_SIZE)
  1919. read_buf_size = MAX_XFR_SIZE;
  1920. if (Temp_buf_size > read_buf_size)
  1921. Temp_buf_size = read_buf_size; /* adjust only if reduction */
  1922. #if 0
  1923. fprintf(stderr, "merge phase adjustment: %d to %d\n",
  1924. Output_buf_size, Temp_buf_size);
  1925. fprintf(stderr, "N_runs: %d, Run_limit: %d\n", N_runs, Run_limit);
  1926. #endif
  1927. /* initialize each run
  1928. */
  1929. for (i = 0; i < N_runs; i++)
  1930. {
  1931. Run[i].index = i;
  1932. for (j = 0; j < N_RUN_BUFS; j++)
  1933. Run[i].buf[j] = Merge_phase_run_begin +
  1934. (i * N_RUN_BUFS + j) * Temp_buf_size;
  1935. Run[i].next_byte = Run[i].buf_begin = Run[i].buf[0];
  1936. Run[i].buf_off = Run[i].begin_off;
  1937. Run[i].buf_bytes = 0;
  1938. Run[i].end_read_off = Run[i].mid_off;
  1939. Run[i].rec = Merge_phase_run_begin +
  1940. (N_runs * N_RUN_BUFS * Temp_buf_size) + (i * Max_rec_bytes_internal);
  1941. Run[i].blks_read = Run[i].blks_scanned = 0;
  1942. Run[i].next = NULL;
  1943. queue_run_read(&Run[i]); /* queue a read of run's first block */
  1944. }
  1945. if (Reverse)
  1946. merge_runs();
  1947. else
  1948. copy_shorts();
  1949. /* adjust temp file ending offsets for each run to include the second
  1950. * "half" of each run.
  1951. */
  1952. for (i = 0; i < N_runs; i++)
  1953. Run[i].end_read_off = Run[i].end_off;
  1954. if (Reverse)
  1955. copy_shorts();
  1956. else
  1957. merge_runs();
  1958. CloseHandle(Temp_handle);
  1959. complete_writes();
  1960. }
  1961. /* CLEAR_RUN - clear the records from memory for the run just written to
  1962. * the temporary file.
  1963. */
  1964. void clear_run()
  1965. {
  1966. Last_recp = Short_recp = End_recp;
  1967. Next_rec = Rec;
  1968. }
  1969. /* SET_LOCALE
  1970. */
  1971. void set_locale()
  1972. {
  1973. if (Locale == NULL)
  1974. setlocale(LC_ALL, ""); /* use system-default locale */
  1975. else if (strcmp(Locale, "C"))
  1976. error(MSG_SORT_INVALID_LOCALE);
  1977. }
  1978. /* MAIN
  1979. */
  1980. int
  1981. _cdecl main(int argc, char *argv[])
  1982. {
  1983. SetThreadUILanguage(0);
  1984. Phase = INPUT_PHASE;
  1985. read_args(argc, argv);
  1986. set_locale();
  1987. init_input_output();
  1988. init_mem();
  1989. sample_input();
  1990. if (!EOF_seen)
  1991. strategy();
  1992. /* generate run(s) */
  1993. do
  1994. {
  1995. if (!EOF_seen)
  1996. read_input();
  1997. if (Last_recp == End_recp) /* if no records were read, ignore run */
  1998. break;
  1999. sort();
  2000. if (!Two_pass)
  2001. {
  2002. if (EOF_seen)
  2003. break;
  2004. else
  2005. init_two_pass();
  2006. }
  2007. write_recs();
  2008. clear_run();
  2009. } while (!EOF_seen);
  2010. Phase = OUTPUT_PHASE;
  2011. review_output_mode();
  2012. if (Two_pass)
  2013. merge_pass();
  2014. else
  2015. write_recs();
  2016. CloseHandle(Output_handle);
  2017. return (0);
  2018. }