System.Data.SQLite
Check-in [fcac33cc7a]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Internal enhancements to the native memory allocation wrapper.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: fcac33cc7a08686a894387d963ea3b9062a77978
User & Date: mistachkin 2018-03-08 20:50:47
Context
2018-03-09
17:25
Add more tests pursuant to ticket [baf42ee135]. check-in: d1b6742e1e user: mistachkin tags: trunk
2018-03-08
20:50
Internal enhancements to the native memory allocation wrapper. check-in: fcac33cc7a user: mistachkin tags: trunk
18:13
Prevent GetSchemaTable from throwing InvalidCastException. Fix for [baf42ee135]. check-in: c956230a3c user: mistachkin tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to System.Data.SQLite/SQLiteModule.cs.

3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284















































































































































3285
3286
3287
3288
3289
3290
3291
....
3302
3303
3304
3305
3306
3307
3308
3309

3310
3311

3312
3313
3314
3315

3316
3317















3318
3319
3320

3321
3322
3323


3324
3325
3326
3327
3328
3329
3330
....
3347
3348
3349
3350
3351
3352
3353
3354























3355
3356

3357
3358
3359
3360
3361

3362

3363
3364
3365
3366
3367
3368
3369
3370
....
3383
3384
3385
3386
3387
3388
3389
3390





























3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
....
4330
4331
4332
4333
4334
4335
4336




















4337
4338
4339
4340
4341
4342
4343

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// The total number of outstanding memory bytes allocated by this
        /// class using the SQLite core library.
        /// </summary>
        private static int bytesAllocated;

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// The maximum number of outstanding memory bytes ever allocated by
        /// this class using the SQLite core library.
        /// </summary>
        private static int maximumBytesAllocated;
#endif
        #endregion
















































































































































        ///////////////////////////////////////////////////////////////////////

        #region Memory Allocation Helper Methods
        /// <summary>
        /// Allocates at least the specified number of bytes of native memory
        /// via the SQLite core library sqlite3_malloc() function and returns
................................................................................
        /// not be allocated.
        /// </returns>
        public static IntPtr Allocate(int size)
        {
            IntPtr pMemory = UnsafeNativeMethods.sqlite3_malloc(size);

#if TRACK_MEMORY_BYTES
            if (pMemory != IntPtr.Zero)

            {
                int blockSize = Size(pMemory);


                if (blockSize > 0)
                {
                    lock (syncRoot)

                    {
                        bytesAllocated += blockSize;
















                        if (bytesAllocated > maximumBytesAllocated)
                            maximumBytesAllocated = bytesAllocated;

                    }
                }
            }


#endif

            return pMemory;
        }

        ///////////////////////////////////////////////////////////////////////

................................................................................
        public static IntPtr AllocateUntracked(int size)
        {
            return UnsafeNativeMethods.sqlite3_malloc(size);
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>























        /// Gets and returns the actual size of the specified memory block
        /// that was previously obtained from the <see cref="Allocate" /> or

        /// <see cref="AllocateUntracked" /> methods or directly from the
        /// SQLite core library.
        /// </summary>
        /// <param name="pMemory">
        /// The native pointer to the memory block previously obtained from the

        /// <see cref="Allocate" /> or <see cref="AllocateUntracked" /> methods

        /// or directly from the SQLite core library.
        /// </param>
        /// <returns>
        /// The actual size, in bytes, of the memory block specified via the
        /// native pointer.
        /// </returns>
        public static int Size(IntPtr pMemory)
        {
................................................................................
#else
            return 0;
#endif
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>





























        /// Frees a memory block previously obtained from the
        /// <see cref="Allocate" /> method.  If the TRACK_MEMORY_BYTES option
        /// was enabled at compile-time, adjusts the number of bytes currently
        /// allocated by this class.
        /// </summary>
        /// <param name="pMemory">
        /// The native pointer to the memory block previously obtained from the
        /// <see cref="Allocate" /> method.
        /// </param>
        public static void Free(IntPtr pMemory)
        {
#if DEBUG
            SQLiteMarshal.CheckAlignment("Free", pMemory, 0, IntPtr.Size);
#endif

#if TRACK_MEMORY_BYTES
            if (pMemory != IntPtr.Zero)
            {
                int blockSize = Size(pMemory);

                if (blockSize > 0)
                {
                    lock (syncRoot)
                    {
                        bytesAllocated -= blockSize;
                    }
                }
            }
#endif

            UnsafeNativeMethods.sqlite3_free(pMemory);
        }

        ///////////////////////////////////////////////////////////////////////

................................................................................
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Private Methods
#if DEBUG




















        internal static void CheckAlignment(
            string type,
            IntPtr pointer,
            int offset,
            int size
            )
        {







|







|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
>
|
<
>
|
<
|
<
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
>
|
<
<
>
>







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
>
|



|
>
|
>
|







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
|
|



|








|
<
<
<
<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
....
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454

3455
3456

3457

3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476


3477
3478


3479
3480
3481
3482
3483
3484
3485
3486
3487
....
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
....
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619











3620
3621
3622
3623
3624
3625
3626
....
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// The total number of outstanding memory bytes allocated by this
        /// class using the SQLite core library.
        /// </summary>
        private static ulong bytesAllocated;

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// The maximum number of outstanding memory bytes ever allocated by
        /// this class using the SQLite core library.
        /// </summary>
        private static ulong maximumBytesAllocated;
#endif
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Memory Tracking Helper Methods
#if TRACK_MEMORY_BYTES
        /// <summary>
        /// Attempts to determine the size of the specified memory block.  If
        /// the <see cref="Size64" /> method can be used, the returned value
        /// may be larger than <see cref="Int32.MaxValue" />.  A message may
        /// be sent to the logging subsystem if an error is encountered.
        /// </summary>
        /// <param name="pMemory">
        /// The native pointer to the memory block previously obtained from
        /// the <see cref="Allocate" />, <see cref="Allocate64" />,
        /// <see cref="AllocateUntracked" />, or
        /// <see cref="Allocate64Untracked" /> methods or directly from the
        /// SQLite core library.
        /// </param>
        /// <returns>
        /// The size of the specified memory block -OR- zero if the 32-bit
        /// signed value reported from the native API was less than zero.
        /// </returns>
        private static ulong GetBlockSize(
            IntPtr pMemory
            )
        {
            ulong ulongSize = 0;

            if (CanUseSize64())
            {
                ulongSize = Size64(pMemory);
            }
            else
            {
                int intSize = Size(pMemory);

                if (intSize > 0)
                {
                    ulongSize = (ulong)intSize;
                }
#if DEBUG
                else if (intSize < 0)
                {
                    SQLiteLog.LogMessage(SQLiteErrorCode.Warning,
                        HelperMethods.StringFormat(CultureInfo.CurrentCulture,
                        "pointer {0} size {1} appears to be negative: {2}",
                        pMemory, intSize,
#if !PLATFORM_COMPACTFRAMEWORK
                        Environment.StackTrace
#else
                        null
#endif
                    ));
                }
#endif
            }

            return ulongSize;
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Adjusts the total number of (tracked) bytes that are currently
        /// considered to be allocated by this class.  The total number is
        /// increased by the total size of the memory block pointed to by
        /// <paramref name="pMemory" />.  If the new total number exceeds
        /// the previously seen maximum, the maximum will be reset.
        /// </summary>
        /// <param name="pMemory">
        /// A native pointer to newly allocated memory.
        /// </param>
        private static void MemoryWasAllocated(
            IntPtr pMemory
            )
        {
            if (pMemory != IntPtr.Zero)
            {
                ulong blockSize = GetBlockSize(pMemory);

                if (blockSize > 0)
                {
                    lock (syncRoot)
                    {
                        bytesAllocated += blockSize;

                        if (bytesAllocated > maximumBytesAllocated)
                            maximumBytesAllocated = bytesAllocated;
                    }
                }
            }
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Adjusts the total number of (tracked) bytes that are currently
        /// considered to be allocated by this class.  The total number is
        /// decreased by the total size of the memory block pointed to by
        /// <paramref name="pMemory" />.
        /// </summary>
        /// <param name="pMemory">
        /// A native pointer to allocated memory that is going to be freed.
        /// </param>
        private static void MemoryIsBeingFreed(
            IntPtr pMemory
            )
        {
            if (pMemory != IntPtr.Zero)
            {
                ulong blockSize = GetBlockSize(pMemory);

                if (blockSize > 0)
                {
                    lock (syncRoot)
                    {
                        bytesAllocated -= blockSize;
                    }
                }
            }
        }
#endif
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Memory Version Helper Methods
        /// <summary>
        /// Determines if the native sqlite3_msize() API can be used, based on
        /// the available version of the SQLite core library.
        /// </summary>
        /// <returns>
        /// Non-zero if the native sqlite3_msize() API property is supported
        /// by the SQLite core library.
        /// </returns>
        private static bool CanUseSize64()
        {
            if (UnsafeNativeMethods.sqlite3_libversion_number() >= 3008007)
                return true;

            return false;
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Memory Allocation Helper Methods
        /// <summary>
        /// Allocates at least the specified number of bytes of native memory
        /// via the SQLite core library sqlite3_malloc() function and returns
................................................................................
        /// not be allocated.
        /// </returns>
        public static IntPtr Allocate(int size)
        {
            IntPtr pMemory = UnsafeNativeMethods.sqlite3_malloc(size);

#if TRACK_MEMORY_BYTES
            MemoryWasAllocated(pMemory);
#endif


            return pMemory;
        }



        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Allocates at least the specified number of bytes of native memory
        /// via the SQLite core library sqlite3_malloc64() function and returns
        /// the resulting native pointer.  If the TRACK_MEMORY_BYTES option
        /// was enabled at compile-time, adjusts the number of bytes currently
        /// allocated by this class.
        /// </summary>
        /// <param name="size">
        /// The number of bytes to allocate.
        /// </param>
        /// <returns>
        /// The native pointer that points to a block of memory of at least the
        /// specified size -OR- <see cref="IntPtr.Zero" /> if the memory could
        /// not be allocated.
        /// </returns>
        public static IntPtr Allocate64(ulong size)
        {


            IntPtr pMemory = UnsafeNativeMethods.sqlite3_malloc64(size);



#if TRACK_MEMORY_BYTES
            MemoryWasAllocated(pMemory);
#endif

            return pMemory;
        }

        ///////////////////////////////////////////////////////////////////////

................................................................................
        public static IntPtr AllocateUntracked(int size)
        {
            return UnsafeNativeMethods.sqlite3_malloc(size);
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Allocates at least the specified number of bytes of native memory
        /// via the SQLite core library sqlite3_malloc64() function and returns
        /// the resulting native pointer without adjusting the number of
        /// allocated bytes currently tracked by this class.  This is useful
        /// when dealing with blocks of memory that will be freed directly by
        /// the SQLite core library.
        /// </summary>
        /// <param name="size">
        /// The number of bytes to allocate.
        /// </param>
        /// <returns>
        /// The native pointer that points to a block of memory of at least the
        /// specified size -OR- <see cref="IntPtr.Zero" /> if the memory could
        /// not be allocated.
        /// </returns>
        public static IntPtr Allocate64Untracked(ulong size)
        {
            return UnsafeNativeMethods.sqlite3_malloc64(size);
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Gets and returns the actual size of the specified memory block
        /// that was previously obtained from the <see cref="Allocate" />,
        /// <see cref="Allocate64" />, <see cref="AllocateUntracked" />, or
        /// <see cref="Allocate64Untracked" /> methods or directly from the
        /// SQLite core library.
        /// </summary>
        /// <param name="pMemory">
        /// The native pointer to the memory block previously obtained from
        /// the <see cref="Allocate" />, <see cref="Allocate64" />,
        /// <see cref="AllocateUntracked" />, or
        /// <see cref="Allocate64Untracked" /> methods or directly from the
        /// SQLite core library.
        /// </param>
        /// <returns>
        /// The actual size, in bytes, of the memory block specified via the
        /// native pointer.
        /// </returns>
        public static int Size(IntPtr pMemory)
        {
................................................................................
#else
            return 0;
#endif
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Gets and returns the actual size of the specified memory block
        /// that was previously obtained from the <see cref="Allocate" />,
        /// <see cref="Allocate64" />, <see cref="AllocateUntracked" />, or
        /// <see cref="Allocate64Untracked" /> methods or directly from the
        /// SQLite core library.
        /// </summary>
        /// <param name="pMemory">
        /// The native pointer to the memory block previously obtained from
        /// the <see cref="Allocate" />, <see cref="Allocate64" />,
        /// <see cref="AllocateUntracked" />, or
        /// <see cref="Allocate64Untracked" /> methods or directly from the
        /// SQLite core library.
        /// </param>
        /// <returns>
        /// The actual size, in bytes, of the memory block specified via the
        /// native pointer.
        /// </returns>
        public static ulong Size64(IntPtr pMemory)
        {
#if DEBUG
            SQLiteMarshal.CheckAlignment("Size64", pMemory, 0, IntPtr.Size);
#endif

            return UnsafeNativeMethods.sqlite3_msize(pMemory);
        }

        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Frees a memory block previously obtained from the
        /// <see cref="Allocate" /> or <see cref="Allocate64" /> methods.  If
        /// the TRACK_MEMORY_BYTES option was enabled at compile-time, adjusts
        /// the number of bytes currently allocated by this class.
        /// </summary>
        /// <param name="pMemory">
        /// The native pointer to the memory block previously obtained from the
        /// <see cref="Allocate" /> or <see cref="Allocate64" /> methods.
        /// </param>
        public static void Free(IntPtr pMemory)
        {
#if DEBUG
            SQLiteMarshal.CheckAlignment("Free", pMemory, 0, IntPtr.Size);
#endif

#if TRACK_MEMORY_BYTES
            MemoryIsBeingFreed(pMemory);











#endif

            UnsafeNativeMethods.sqlite3_free(pMemory);
        }

        ///////////////////////////////////////////////////////////////////////

................................................................................
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Private Methods
#if DEBUG
        /// <summary>
        /// Attempts to verify that the specified native pointer is properly
        /// aligned for the size of the data value.  If that is not the case,
        /// a message will be sent to the logging subsystem.
        /// </summary>
        /// <param name="type">
        /// The type of operation being performed by the caller.  This value
        /// may be used within diagnostic messages.
        /// </param>
        /// <param name="pointer">
        /// The <see cref="IntPtr" /> object instance representing the base
        /// memory location.
        /// </param>
        /// <param name="offset">
        /// The integer offset from the base memory location where the data
        /// value to be read or written.
        /// </param>
        /// <param name="size">
        /// The size, in bytes, of the data value.
        /// </param>
        internal static void CheckAlignment(
            string type,
            IntPtr pointer,
            int offset,
            int size
            )
        {

Changes to System.Data.SQLite/UnsafeNativeMethods.cs.

3360
3361
3362
3363
3364
3365
3366







3367
3368
3369
3370














3371
3372
3373
3374
3375
3376
3377
....
4064
4065
4066
4067
4068
4069
4070


4071
4072
4073
4074
4075
4076
4077
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_malloc(int n);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else







    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_realloc(IntPtr p, int n);















#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern void sqlite3_free(IntPtr p);

................................................................................
#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_mprintf(IntPtr format, __arglist);
    #endregion



    // SQLite API calls that are provided by "well-known" extensions that may be statically
    // linked with the SQLite core native library currently in use.
    #region extension sqlite api calls
    #region virtual table
#if INTEROP_VIRTUAL_TABLE
#if !PLATFORM_COMPACTFRAMEWORK







>
>
>
>
>
>
>




>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>







3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
....
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_malloc(int n);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_malloc64(ulong n);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_realloc(IntPtr p, int n);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_realloc64(IntPtr p, ulong n);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern ulong sqlite3_msize(IntPtr p);

#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern void sqlite3_free(IntPtr p);

................................................................................
#if !PLATFORM_COMPACTFRAMEWORK
    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
#else
    [DllImport(SQLITE_DLL)]
#endif
    internal static extern IntPtr sqlite3_mprintf(IntPtr format, __arglist);
    #endregion

    ///////////////////////////////////////////////////////////////////////////

    // SQLite API calls that are provided by "well-known" extensions that may be statically
    // linked with the SQLite core native library currently in use.
    #region extension sqlite api calls
    #region virtual table
#if INTEROP_VIRTUAL_TABLE
#if !PLATFORM_COMPACTFRAMEWORK