public RC SorterRewind(Context ctx, VdbeCursor cursor, ref bool eof) { VdbeSorter sorter = cursor.Sorter; Debug.Assert(sorter != null); // If no data has been written to disk, then do not do so now. Instead, sort the VdbeSorter.pRecord list. The vdbe layer will read data directly // from the in-memory list. if (sorter.PMAs == 0) { eof = (sorter.Record == null); Debug.Assert(sorter.Trees.data = null); return(VdbeSorterSort(cursor)); } // Write the current in-memory list to a PMA. RC rc = VdbeSorterListToPMA(ctx, cursor); if (rc != RC.OK) { return(rc); } // Allocate space for aIter[] and aTree[]. int iters = sorter.PMAs; // Number of iterators used if (iters > SORTER_MAX_MERGE_COUNT) { iters = SORTER_MAX_MERGE_COUNT; } Debug.Assert(iters > 0); int n = 2; while (n < iters) { n += n; // Power of 2 >= iters } int bytes = n * (sizeof(int) + sizeof(VdbeSorterIter)); // Bytes of space required for aIter/aTree sorter.Iters = (VdbeSorterIter)C._tagalloc(ctx, bytes); if (sorter.Iters == null) { return(RC.NOMEM); } sorter.Trees = sorter.Iters[n]; sorter.Trees.length = n; int newIdx; // Index of new, merged, PMA VFile temp2 = null; // Second temp file to use long write2 = 0; // Write offset for pTemp2 do { for (newIdx = 0; rc == RC.OK && newIdx * SORTER_MAX_MERGE_COUNT < sorter.PMAs; newIdx++) { FileWriter writer; writer._memset(); // Object used to write to disk // If there are SORTER_MAX_MERGE_COUNT or less PMAs in file pTemp1, initialize an iterator for each of them and break out of the loop. // These iterators will be incrementally merged as the VDBE layer calls sqlite3VdbeSorterNext(). // // Otherwise, if pTemp1 contains more than SORTER_MAX_MERGE_COUNT PMAs, initialize interators for SORTER_MAX_MERGE_COUNT of them. These PMAs // are merged into a single PMA that is written to file pTemp2. long writes; // Number of bytes in new PMA rc = VdbeSorterInitMerge(ctx, cursor, ref writes); Debug.Assert(rc != RC.OK || sorter.Iters[sorter.Trees[1]].File); if (rc != RC.OK || sorter.PMAs <= SORTER_MAX_MERGE_COUNT) { break; } // Open the second temp file, if it is not already open. if (temp2 == null) { Debug.Assert(write2 == 0); rc = VdbeSorterOpenTempFile(ctx, ref temp2); } if (rc == RC.OK) { bool eof = false; FileWriterInit(ctx, temp2, ref writer, write2); FileWriterWriteVarint(writer, writes); while (rc == RC.OK && !eof) { VdbeSorterIter iter = sorter.Iters[sorter.Trees[1]]; Debug.Assert(iter.File); FileWriterWriteVarint(writer, iter.Key.length); FileWriterWrite(writer, iter.Key, iter.Key.length); rc = SorterNext(ctx, cursor, eof); } RC rc2 = FileWriterFinish(ctx, writer, write2); if (rc == RC.OK) { rc = rc2; } } } if (sorter.PMAs <= SORTER_MAX_MERGE_COUNT) { break; } else { VFile tmp = sorter.Temp1; sorter.PMAs = newIdx; sorter.Temp1 = temp2; temp2 = tmp; sorter.WriteOffset = write2; sorter.ReadOffset = 0; write2 = 0; } } while (rc == RC.OK); if (temp2) { temp2.CloseAndFree(); } eof = (sorter.Iters[sorter.Trees[1]].File == null); return(rc); }