Exemple #1
0
        static RC VdbeSorterInitMerge(Context ctx, VdbeCursor cursor, ref long bytes)
        {
            VdbeSorter sorter = cursor, Sorter;
            long       bytes2 = 0; // Total bytes in all opened PMAs
            RC         rc     = RC.OK;
            // Initialize the iterators.
            int i; // Used to iterator through aIter[]

            for (i = 0; i < SORTER_MAX_MERGE_COUNT; i++)
            {
                VdbeSorterIter iter = sorter.Iters[i];
                rc = VdbeSorterIterInit(ctx, sorter, sorter.ReadOffset, iter, ref bytes2);
                sorter.ReadOffset = iter.Eof;
                Debug.Assert(rc != RC.OK || sorter.ReadOffset <= sorter.WriteOffset);
                if (rc != RC.OK || sorter.ReadOffset >= sorter.WriteOffset)
                {
                    break;
                }
            }
            // Initialize the aTree[] array.
            for (i = sorter.Trees.length - 1; rc == RC.OK && i > 0; i--)
            {
                rc = VdbeSorterDoCompare(cursor, i);
            }
            bytes = bytes2;
            return(rc);
        }
Exemple #2
0
        static RC VdbeSorterIterVarint(Context ctx, VdbeSorterIter p, out ulong out_)
        {
            int bufferIdx = (int)(p.ReadOffset % p.Buffer.length);

            if (bufferIdx != 0 && (p.Buffer.length - bufferIdx) >= 9)
            {
                p.ReadOffset += ConvertEx.GetVarint(p.Buffer[bufferIdx], out out_);
            }
            else
            {
                byte[] varint = new byte[16]; byte[] a;
                int    i = 0;
                do
                {
                    RC rc = VdbeSorterIterRead(ctx, p, 1, ref a);
                    if (rc != 0)
                    {
                        return(rc);
                    }
                    varint[(i++) & 0xf] = a[0];
                } while ((a[0] & 0x80) != 0);
                ConvertEx.GetVarint(varint, out out_);
            }
            return(RC.OK);
        }
Exemple #3
0
 static object VdbeSorterRowkey(VdbeSorter sorter, out int keyLength)
 {
     if (sorter.Trees.data != null)
     {
         VdbeSorterIter iter = sorter.Iters[sorter.Trees.data[1]];
         keyLength = iter.Key.length;
         return(iter.Key);
     }
     keyLength = sorter.Record.N;
     return(sorter.Record.P);
 }
Exemple #4
0
        static RC VdbeSorterIterInit(Context ctx, VdbeSorter sorter, long start, VdbeSorterIter iter, ref long bytes)
        {
            Debug.Assert(sorter.WriteOffset > start);
            Debug.Assert(iter.Alloc.data == null);
            Debug.Assert(iter.Buffer.data == null);
            int bufferLength = ctx.DBs[0].Bt.GetPageSize();

            iter.File          = sorter.Temp1;
            iter.ReadOffset    = start;
            iter.Alloc.length  = 128;
            iter.Alloc.data    = (byte[])C._tagalloc(ctx, iter.Alloc.length);
            iter.Buffer.length = bufferLength;
            iter.Buffer.data   = (byte[])C._tagalloc(ctx, bufferLength);
            RC rc = RC.OK;

            if (iter.Buffer.data == null)
            {
                rc = RC.NOMEM;
            }
            else
            {
                int bufferIdx = start % bufferLength;
                if (bufferIdx != 0)
                {
                    int read = bufferLength - bufferIdx;
                    if ((start + read) > sorter.WriteOffset)
                    {
                        read = (int)(sorter.WriteOffset - start);
                    }
                    rc = sorter.Temp1.Read(iter.Buffer[bufferIdx], read, start);
                    Debug.Assert(rc != RC.IOERR_SHORT_READ);
                }
                if (rc == RC.OK)
                {
                    iter.Eof = sorter.WriteOffset;
                    ulong bytes2; // Size of PMA in bytes
                    rc       = VdbeSorterIterVarint(ctx, iter, ref bytes2);
                    iter.Eof = iter.ReadOffset + bytes2;
                    bytes   += bytes2;
                }
            }
            if (rc == RC.OK)
            {
                rc = VdbeSorterIterNext(ctx, iter);
            }
            return(rc);
        }
Exemple #5
0
        static RC VdbeSorterIterNext(Context ctx, VdbeSorterIter iter)
        {
            if (iter.ReadOffset >= iter.Eof)
            {
                VdbeSorterIterZero(ctx, iter); // This is an EOF condition
                return(RC.OK);
            }
            ulong recordSize; // Size of record in bytes
            RC    rc = VdbeSorterIterVarint(ctx, iter, ref recordSize);

            if (rc == RC.OK)
            {
                iter.Key.length = (int)recordSize;
                rc = VdbeSorterIterRead(ctx, iter, (int)recordSize, ref iter.Key.data);
            }
            return(rc);
        }
Exemple #6
0
        static RC VdbeSorterDoCompare(VdbeCursor cursor, int idx)
        {
            VdbeSorter sorter = cursor.Sorter;

            Debug.Assert(idx < sorter.Trees.length && idx > 0);

            int i1;
            int i2;

            if (idx >= (sorter.Trees.length / 2))
            {
                i1 = (idx - sorter.Trees.length / 2) * 2;
                i2 = i1 + 1;
            }
            else
            {
                i1 = sorter.Trees[idx * 2];
                i2 = sorter.Trees[idx * 2 + 1];
            }
            VdbeSorterIter p1 = sorter.Iters[i1];
            VdbeSorterIter p2 = sorter.Iters[i2];

            int i;

            if (p1.File == null)
            {
                i = i2;
            }
            else if (p2.File == null)
            {
                i = i1;
            }
            else
            {
                Debug.Assert(sorter.Unpacked != null); // allocated in vdbeSorterMerge()
                int r;
                VdbeSorterCompare(cursor, 0, p1.Key, p1.Key.length, p2.Key, p2.Key.length, ref r);
                i = (r <= 0 ? i1 : i2);
            }
            sorter.Trees[idx] = i;
            return(RC.OK);
        }
Exemple #7
0
        static RC VdbeSorterIterRead(Context ctx, VdbeSorterIter p, int bytes, ref byte[] out_)
        {
            Debug.Assert(p.Buffer.data != null);

            // If there is no more data to be read from the buffer, read the next p->nBuffer bytes of data from the file into it. Or, if there are less
            // than p->nBuffer bytes remaining in the PMA, read all remaining data.
            int bufferIdx = (int)(p.ReadOffset % p.Buffer.length); // Offset within buffer to read from

            if (bufferIdx == 0)
            {
                // Determine how many bytes of data to read.
                int read = (int)((p.Eof - p.ReadOffset) > p.Buffer.length ? p.Buffer.length : p.Eof - p.ReadOffset); // Bytes to read from disk
                Debug.Assert(read > 0);

                // Read data from the file. Return early if an error occurs.
                RC rc = p.File.Read(p.Buffer, read, p.ReadOffset);
                Debug.Assert(rc != RC.IOERR_SHORT_READ);
                if (rc != RC.OK)
                {
                    return(rc);
                }
            }
            int avail = p.Buffer.length - bufferIdx; // Bytes of data available in buffer

            if (bytes <= avail)
            {
                // The requested data is available in the in-memory buffer. In this case there is no need to make a copy of the data, just return a
                // pointer into the buffer to the caller.
                out_          = p.Buffer[bufferIdx];
                p.ReadOffset += bytes;
            }
            // The requested data is not all available in the in-memory buffer. In this case, allocate space at p->aAlloc[] to copy the requested
            // range into. Then return a copy of pointer p->aAlloc to the caller.
            else
            {
                // Extend the p->aAlloc[] allocation if required.
                if (p.Alloc.length < bytes)
                {
                    int newSize = p.Alloc.length * 2;
                    while (bytes > newSize)
                    {
                        newSize = newSize * 2;
                    }
                    p.Alloc.data = (byte[])C._tagrealloc(ctx, 0, p.Alloc.data, newSize);
                    if (p.Alloc.data == null)
                    {
                        return(RC.NOMEM);
                    }
                    p.Alloc.length = newSize;
                }

                // Copy as much data as is available in the buffer into the start of p->aAlloc[].
                C._memcpy(p.Alloc.data, p.Buffer[bufferIdx], avail);
                p.ReadOffset += avail;

                // The following loop copies up to p->nBuffer bytes per iteration into the p->aAlloc[] buffer.
                int remaining = bytes - avail; // Bytes remaining to copy
                while (remaining > 0)
                {
                    int copy = remaining; // Number of bytes to copy
                    if (remaining > p.Buffer.length)
                    {
                        copy = p.Buffer.length;
                    }
                    byte[] next; // Pointer to buffer to copy data from
                    RC     rc = VdbeSorterIterRead(ctx, p, copy, ref next);
                    if (rc != RC.OK)
                    {
                        return(rc);
                    }
                    Debug.Assert(next != p.Alloc);
                    C._memcpy(p.Alloc[bytes - remaining], next, copy);
                    remaining -= copy;
                }

                out_ = p.Alloc;
            }
            return(RC.OK);
        }
Exemple #8
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);
        }
Exemple #9
0
        public const int SORTER_MAX_MERGE_COUNT = 16; // Maximum number of segments to merge in a single pass.

        #endregion

        #region Sorter Iter

        static void VdbeSorterIterZero(Context ctx, VdbeSorterIter iter)
        {
            C._tagfree(ctx, ref iter.Alloc.data);
            C._tagfree(ctx, ref iter.Buffer.data);
            iter._memset();
        }
Exemple #10
0
        static RC VdbeSorterIterRead(Context ctx, VdbeSorterIter p, int bytes, ref byte[] out_)
        {
            Debug.Assert(p.Buffer.data != null);

            // If there is no more data to be read from the buffer, read the next p->nBuffer bytes of data from the file into it. Or, if there are less
            // than p->nBuffer bytes remaining in the PMA, read all remaining data.
            int bufferIdx = (int)(p.ReadOffset % p.Buffer.length); // Offset within buffer to read from
            if (bufferIdx == 0)
            {
                // Determine how many bytes of data to read.
                int read = (int)((p.Eof - p.ReadOffset) > p.Buffer.length ? p.Buffer.length : p.Eof - p.ReadOffset); // Bytes to read from disk
                Debug.Assert(read > 0);

                // Read data from the file. Return early if an error occurs.
                RC rc = p.File.Read(p.Buffer, read, p.ReadOffset);
                Debug.Assert(rc != RC.IOERR_SHORT_READ);
                if (rc != RC.OK) return rc;
            }
            int avail = p.Buffer.length - bufferIdx; // Bytes of data available in buffer

            if (bytes <= avail)
            {
                // The requested data is available in the in-memory buffer. In this case there is no need to make a copy of the data, just return a 
                // pointer into the buffer to the caller.
                out_ = p.Buffer[bufferIdx];
                p.ReadOffset += bytes;
            }
            // The requested data is not all available in the in-memory buffer. In this case, allocate space at p->aAlloc[] to copy the requested
            // range into. Then return a copy of pointer p->aAlloc to the caller.
            else
            {
                // Extend the p->aAlloc[] allocation if required.
                if (p.Alloc.length < bytes)
                {
                    int newSize = p.Alloc.length * 2;
                    while (bytes > newSize) newSize = newSize * 2;
                    p.Alloc.data = (byte[])C._tagrealloc(ctx, 0, p.Alloc.data, newSize);
                    if (p.Alloc.data == null) return RC.NOMEM;
                    p.Alloc.length = newSize;
                }

                // Copy as much data as is available in the buffer into the start of p->aAlloc[].
                C._memcpy(p.Alloc.data, p.Buffer[bufferIdx], avail);
                p.ReadOffset += avail;

                // The following loop copies up to p->nBuffer bytes per iteration into the p->aAlloc[] buffer.
                int remaining = bytes - avail; // Bytes remaining to copy
                while (remaining > 0)
                {
                    int copy = remaining; // Number of bytes to copy
                    if (remaining > p.Buffer.length) copy = p.Buffer.length;
                    byte[] next; // Pointer to buffer to copy data from
                    RC rc = VdbeSorterIterRead(ctx, p, copy, ref next);
                    if (rc != RC.OK) return rc;
                    Debug.Assert(next != p.Alloc);
                    C._memcpy(p.Alloc[bytes - remaining], next, copy);
                    remaining -= copy;
                }

                out_ = p.Alloc;
            }
            return RC.OK;
        }
Exemple #11
0
        public const int SORTER_MAX_MERGE_COUNT = 16; // Maximum number of segments to merge in a single pass.

        #endregion

        #region Sorter Iter

        static void VdbeSorterIterZero(Context ctx, VdbeSorterIter iter)
        {
            C._tagfree(ctx, ref iter.Alloc.data);
            C._tagfree(ctx, ref iter.Buffer.data);
            iter._memset();
        }
Exemple #12
0
 static RC VdbeSorterIterInit(Context ctx, VdbeSorter sorter, long start, VdbeSorterIter iter, ref long bytes)
 {
     Debug.Assert(sorter.WriteOffset > start);
     Debug.Assert(iter.Alloc.data == null);
     Debug.Assert(iter.Buffer.data == null);
     int bufferLength = ctx.DBs[0].Bt.GetPageSize();
     iter.File = sorter.Temp1;
     iter.ReadOffset = start;
     iter.Alloc.length = 128;
     iter.Alloc.data = (byte[])C._tagalloc(ctx, iter.Alloc.length);
     iter.Buffer.length = bufferLength;
     iter.Buffer.data = (byte[])C._tagalloc(ctx, bufferLength);
     RC rc = RC.OK;
     if (iter.Buffer.data == null)
         rc = RC.NOMEM;
     else
     {
         int bufferIdx = start % bufferLength;
         if (bufferIdx != 0)
         {
             int read = bufferLength - bufferIdx;
             if ((start + read) > sorter.WriteOffset)
                 read = (int)(sorter.WriteOffset - start);
             rc = sorter.Temp1.Read(iter.Buffer[bufferIdx], read, start);
             Debug.Assert(rc != RC.IOERR_SHORT_READ);
         }
         if (rc == RC.OK)
         {
             iter.Eof = sorter.WriteOffset;
             ulong bytes2; // Size of PMA in bytes
             rc = VdbeSorterIterVarint(ctx, iter, ref bytes2);
             iter.Eof = iter.ReadOffset + bytes2;
             bytes += bytes2;
         }
     }
     if (rc == RC.OK)
         rc = VdbeSorterIterNext(ctx, iter);
     return rc;
 }
Exemple #13
0
 static RC VdbeSorterIterNext(Context ctx, VdbeSorterIter iter)
 {
     if (iter.ReadOffset >= iter.Eof)
     {
         VdbeSorterIterZero(ctx, iter); // This is an EOF condition
         return RC.OK;
     }
     ulong recordSize; // Size of record in bytes
     RC rc = VdbeSorterIterVarint(ctx, iter, ref recordSize);
     if (rc == RC.OK)
     {
         iter.Key.length = (int)recordSize;
         rc = VdbeSorterIterRead(ctx, iter, (int)recordSize, ref iter.Key.data);
     }
     return rc;
 }
Exemple #14
0
 static RC VdbeSorterIterVarint(Context ctx, VdbeSorterIter p, out ulong out_)
 {
     int bufferIdx = (int)(p.ReadOffset % p.Buffer.length);
     if (bufferIdx != 0 && (p.Buffer.length - bufferIdx) >= 9)
         p.ReadOffset += ConvertEx.GetVarint(p.Buffer[bufferIdx], out out_);
     else
     {
         byte[] varint = new byte[16]; byte[] a;
         int i = 0;
         do
         {
             RC rc = VdbeSorterIterRead(ctx, p, 1, ref a);
             if (rc != 0) return rc;
             varint[(i++) & 0xf] = a[0];
         } while ((a[0] & 0x80) != 0);
         ConvertEx.GetVarint(varint, out out_);
     }
     return RC.OK;
 }