Beispiel #1
0
        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);
        }