diff --git a/CMakeLists.txt b/CMakeLists.txt
index 21799e5a..362281d9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -51,6 +51,13 @@ else()
message(FATAL_ERROR "NOTE: NOT setting 64-bit OR 32-bit symbols")
endif()
+# Set the C++ standard to C++17
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF) # Optional: disables compiler-specific extensions like MSVC's /TP
+# Alternative, is this other way to do it, that is MSVC specific (so would need to be in if MSVC clause of some kind)
+# add_compile_options(/std:c++17)
+
# CMake chooses reasonable prefixes and suffixes for Unix-like platforms,
# but we'd rather keep them the same for now. May revisit this decision later.
set(CMAKE_STATIC_LIBRARY_PREFIX)
@@ -140,8 +147,21 @@ link_libraries(
${ESE_RELEASE_LIBRARIES}
)
+# Global ESE project defines
+add_compile_definitions(
+ OS_LAYER_USE_NEW_OVERRIDE
+)
+
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# Using Microsoft Visual C++
+
+ # The _HAS_STD_BYTE=0 came in along with the CMAKE_CXX_STANDARD 17 (and was stdcpp17 change
+ # from the .vcxproj project file world) to make ESE code not conflict. Research suggested this is only need for MSVC, so it is
+ # set in here.
+ add_compile_definitions(
+ _HAS_STD_BYTE=0
+ )
+
add_compile_options(
/Oi # generate intrinsic functions
/Ot
@@ -158,6 +178,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
/Gy # function-level linking
/Zc:wchar_t-
/Zc:forScope
+ /Zc:externConstexpr
/Zc:inline-
/GR-
/TP
diff --git a/dev/ese/published/inc/cc.hxx b/dev/ese/published/inc/cc.hxx
index 701d3a18..5f848e3d 100644
--- a/dev/ese/published/inc/cc.hxx
+++ b/dev/ese/published/inc/cc.hxx
@@ -11,293 +11,300 @@
// Some interesting defines we might try ...
#ifdef _MSC_VER
-#ifndef WINNT
-//#define WINNT 1
-#endif
+
+ #ifndef WINNT
+ //#define WINNT 1
+ #endif
+
#else
-//#define UNIX 1
-//#define _GCC 1
+
+ //#define UNIX 1
+ //#define _GCC 1
+
#endif
-//
-// SAL is not defined everywhere
-//
+#include
-#ifndef _MSC_VER
-
-#define _In_
-#define _Out_
-#define _Out_opt_
-#define _Inout_
-#define _In_count_(x)
-#define _In_reads_(x)
-#define _In_reads_opt_(x)
-#define _In_reads_bytes_(x)
-#define _In_reads_bytes_opt_(x)
-#define _Inout_updates_bytes_(x)
-#define _Inout_updates_opt_(x)
-#define _Out_writes_(x)
-#define _Out_writes_to_opt_(x, y)
-#define _Out_writes_bytes_(x)
-#define _Out_writes_bytes_opt_(x)
-#define _Out_writes_bytes_to_(x, y)
-#define _Out_writes_bytes_to_opt_(x, y)
-#define _Outptr_result_buffer_(x)
-#define _Null_terminated_
-#define _Return_type_success_(x)
-#define _Field_size_(x)
-#define _Field_size_opt_(x)
-#define _Field_size_bytes_(x)
-#define _Field_size_bytes_opt_(x)
-
-#else // _MSC_VER
-
-#include
-
-// These conflict with definitions in headers such as on non-Windows platforms.
-// _In_ and _Out_ should be used instead anyway, according to Microsoft's SAL documentation.
-//
-// Unfortunately, can't easily redefine __in and __out because these old-style annotations
-// crept back into the Windows headers ntsecapi.h and dbgeng.h, which we include
//
-// #undef __in
-// #undef __out
+// Source Annotation Language (SAL)
//
-// #define __in Use_In_instead_of__in
-// #define __out Use_Out_instead_of__out
-
-#endif // !_MSC_VER
-// Like SAL this produces a compile-time assert ...
-#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
+#ifdef _MSC_VER
+ #include
+
+ // These conflict with definitions in headers such as on non-Windows platforms.
+ // _In_ and _Out_ should be used instead anyway, according to Microsoft's SAL documentation.
+ //
+ // Unfortunately, can't easily redefine __in and __out because these old-style annotations
+ // crept back into the Windows headers ntsecapi.h and dbgeng.h, which we include
+ //
+ // #undef __in
+ // #undef __out
+ //
+ // #define __in Use_In_instead_of__in
+ // #define __out Use_Out_instead_of__out
+
+#else // !_MSC_VER
+
+ // SAL is not defined everywhere
+ //
+
+ #define _In_
+ #define _Out_
+ #define _Out_opt_
+ #define _Inout_
+ #define _In_count_(x)
+ #define _In_reads_(x)
+ #define _In_reads_opt_(x)
+ #define _In_reads_bytes_(x)
+ #define _In_reads_bytes_opt_(x)
+ #define _Inout_updates_bytes_(x)
+ #define _Inout_updates_opt_(x)
+ #define _Out_writes_(x)
+ #define _Out_writes_to_opt_(x, y)
+ #define _Out_writes_bytes_(x)
+ #define _Out_writes_bytes_opt_(x)
+ #define _Out_writes_bytes_to_(x, y)
+ #define _Out_writes_bytes_to_opt_(x, y)
+ #define _Outptr_result_buffer_(x)
+ #define _Null_terminated_
+ #define _Return_type_success_(x)
+ #define _Field_size_(x)
+ #define _Field_size_opt_(x)
+ #define _Field_size_bytes_(x)
+ #define _Field_size_bytes_opt_(x)
+
+#endif
//
// Types
//
-#ifndef _MSC_VER
-// the required intXX_t types are std on VC - windows as well, but we can't define
-// them commonly b/c we get redefinition of basic types conflicts on WINNT.
-#include
-#endif
-
// odd void indirection
#pragma push_macro( "VOID" )
#undef VOID
-typedef void VOID;
+typedef void VOID;
#pragma pop_macro( "VOID" )
-typedef VOID * PVOID;
-
-// Boolean types
-//
-
-// ESE's standard BOOL is 4 bytes, unlike bool which is 1 byte. This is used
-// in a bunch of persisted structures and such, so changing it to bool is non-
-// trivial. We will fix it at 4 bytes for now. Besides if you really wanted
-// to save space, just use a bit-field.
-#ifdef _MSC_VER
- typedef int BOOL;
-#else
- typedef int32_t BOOL;
-#endif
-
-// Another complication, the signed BOOL and C++ bool are unsuitable for bit fields
-// of 1-bit size, due to the way C sign extends 1 to be 0xFFFFFFFF. This type is
-// designed for usage in bit fields involving 4-byte types (INT, ULONG, etc) without
-// these sign extension problems.
-typedef unsigned int FLAG32;
-
-#define fFalse BOOL( 0 )
-#define fTrue BOOL( !0 )
+typedef VOID * PVOID;
// String types
+// We base our strings off of char from the C++ standard and wchar_t
+typedef char CHAR;
+typedef unsigned char UCHAR;
+typedef _Null_terminated_ CHAR * PSTR;
+typedef _Null_terminated_ const CHAR * PCSTR;
+typedef wchar_t WCHAR;
+typedef _Null_terminated_ WCHAR * PWSTR;
+typedef _Null_terminated_ const WCHAR * PCWSTR;
+
+// We'll base our integral types on the types from stdint.h, a standards-defined file that's guaranteed to be
+// equivalent on all platforms.
//
+#include
-typedef char CHAR;
-typedef CHAR *LPSTR;
-
-
-// Basic integer types
+// Constant sized integer types
//
-
-#ifdef _MSC_VER
- typedef short SHORT, *PSHORT;
- typedef unsigned short USHORT, *PUSHORT;
- typedef int INT, *PINT;
- typedef unsigned int UINT, *PUINT;
- typedef long LONG, *PLONG;
- typedef unsigned long ULONG, *PULONG;
- typedef long long LONGLONG, *PLONGLONG;
- typedef unsigned long long ULONGLONG, *PULONGLONG;
-#else
- // On most other platforms, int and long are 64-bit on 64-bit platforms, but the ESE format
- // is dependent upon LONG being 32-bits.
- typedef int16_t SHORT;
- typedef uint16_t USHORT;
- typedef int32_t INT;
- typedef uint32_t UINT;
- typedef int32_t LONG;
- typedef uint32_t ULONG;
- typedef int64_t LONGLONG;
- typedef uint64_t ULONGLONG;
-#endif
-
-// Machine word types
+typedef int8_t INT8;
+typedef uint8_t UINT8;
+typedef int16_t INT16;
+typedef uint16_t UINT16;
+typedef int32_t INT32;
+typedef uint32_t UINT32;
+typedef int64_t INT64;
+typedef uint64_t UINT64;
+
+// Variable sized integer types, based on pointer-sized integer types
//
+typedef intptr_t INT_PTR;
+typedef uintptr_t UINT_PTR;
+typedef uintptr_t SIZE_T;
-typedef unsigned char BYTE, *PBYTE;
-typedef USHORT WORD, *PWORD;
-typedef ULONG DWORD, *PDWORD;
-typedef ULONGLONG QWORD, *PQWORD;
-
-// Pointer types
+// Idealized machine word types
//
+typedef UINT8 BYTE;
+typedef UINT16 WORD;
+typedef unsigned long DWORD; // Note the unsafe use of long. Currently required to interop with
+ // Windows headers without a bunch of casts.
+typedef UINT64 QWORD;
+
+// ESE's standard BOOL is 4 bytes, unlike C++'s bool which is 1 byte. This is
+// used in a bunch of persisted structures and such, so changing it to bool is
+// non-trivial. We will fix it at 4 bytes. Besides if you really wanted to
+// save space, just use a bit-field.
+typedef INT32 BOOL;
+#define fFalse BOOL( 0 )
+#define fTrue BOOL( !0 )
-#if defined(_WIN64)
- #ifdef _MSC_VER
- typedef unsigned __int64 UNSIGNED_PTR;
- typedef __int64 SIGNED_PTR;
- #else // !_MSC_VER
- typedef unsigned long UNSIGNED_PTR;
- typedef long SIGNED_PTR;
- #endif // _MSC_VER
-#else
- typedef unsigned long UNSIGNED_PTR;
- typedef long SIGNED_PTR;
-#endif
-
-
-typedef LONGLONG LONG64;
-typedef unsigned int DWORD32;
-typedef unsigned int ULONG32;
-typedef ULONGLONG ULONG64;
-
-
-//typedef long long INT64;
-//typedef unsigned long long UINT64;
-#ifndef _MSC_VER
- typedef long long __int64;
-#endif
-
-#if defined(_WIN64)
- #ifdef _MSC_VER
-
- typedef __int64 INT_PTR, *PINT_PTR;
- typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
-
- typedef __int64 LONG_PTR, *PLONG_PTR;
- typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
-
- #else // !_MSC_VER
-
- typedef unsigned long ULONG_PTR;
- typedef long LONG_PTR;
-
- #endif // _MSC_VER
-#else
-
- typedef __w64 int INT_PTR, *PINT_PTR;
- typedef __w64 unsigned int UINT_PTR, *PUINT_PTR;
-
- typedef __w64 long LONG_PTR, *PLONG_PTR;
- typedef __w64 unsigned long ULONG_PTR, *PULONG_PTR;
-
-#endif
-
-typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
-typedef ULONG_PTR SIZE_T, *PSIZE_T;
+// Another complication, the signed BOOL and C++ bool are unsuitable for bit fields
+// of 1-bit size, due to the way C++ sign extends 1 to be 0xFFFFFFFF. This type is
+// designed for usage in bit fields involving 4-byte types without thse sign extension
+// problems.
+typedef UINT32 FLAG32;
+
+// A Note about UINT32 and LONG.
+// ESE code has traditionally intermingled "int" based types and "long" based types. This
+// is because, in Windows, both are 32 bit unsigned integral values. And it's totally safe
+// since the compiler will coerce between the two AND the two have the same range, bit layout, etc.
+// HOWEVER.
+// Because they are different base types, the compiler thinks that (int *) and (long *) are
+// too different to coerce. That's why we have random casts between the two. The C++ spec
+// says that it is permissible for a compiler to play tricks such that it actually isn't safe
+// to just cast an "int *" to a "long *". And it's possible that systems such as GCC on Linux
+// actually do play games that make that unsafe (even if they were the same number of bytes,
+// which they aren't on Linux). But here, now, with MSVC and Windows, it's safe. Furthermore,
+// we actually do it all the time. We're working towards a reorganization of our
+// base types such that we don't mix and match those base types. Until that's done and clean,
+// we need the following:
+
+// These eventually should only be in the OS directory. They're for places where it's mandatory
+// to use "long" to interact with the OS in code that otherwise wishes to restrict itself to the
+// "core" ESE data types defined in this file. The most likely places to use them will be in
+// casts and in mirrored declarations of OS provided functions (i.e. not picked up from a header).
+typedef long OS_WIN_LONG;
+typedef unsigned long OS_WIN_ULONG;
+typedef unsigned long OS_WIN_DWORD;
+typedef long * OS_WIN_PLONG;
+typedef unsigned long * OS_WIN_PULONG;
+typedef unsigned long * OS_WIN_PDWORD;
+
+// We're going to get rid of these from this file as we reorganize to the base types above.
+// This file holds the minimal type definitions that the "core" implementation of ESE may use.
+// There are other "non-core" portions (like the perfmon code) that will be allowed to use
+// a wider variety of types in order to interact with Windows. Those types will be defined
+// elsewhere and only included where absolutely needed.
+typedef INT16 SHORT;
+typedef INT32 INT;
+typedef INT64 LONG64;
+typedef INT64 LONGLONG;
+typedef UINT8 * PBYTE;
+typedef UINT16 USHORT;
+typedef UINT32 DWORD32; // Unlike DWORD, not really dereived from "long" type.
+typedef UINT32 UINT;
+typedef UINT32 ULONG32; // Not really derived from "long" type.
+typedef UINT64 ULONG64;
+typedef UINT64 ULONGLONG;
+typedef UINT64 * PULONGLONG;
+typedef INT_PTR LONG_PTR; // Not really derived from "long" type.
+typedef INT_PTR SIGNED_PTR;
+typedef UINT_PTR DWORD_PTR; // Not really derived from "long" type.
+typedef UINT_PTR ULONG_PTR; // Not really derived from "long" type.
+typedef UINT_PTR UNSIGNED_PTR;
+
+typedef long LONG; // Note the problematic "long" derived type.
+typedef unsigned long ULONG; // Note the problematic "long" derived type.
+typedef unsigned long * PULONG; // Note the problematic "long" derived type.
+
+typedef PSTR LPSTR; // The LP stands for "Long Pointer" which has been obsolete for decades.
+typedef PCSTR LPCSTR; // The LP stands for "Long Pointer" which has been obsolete for decades.
+typedef PWSTR LPWSTR; // The LP stands for "Long Pointer" which has been obsolete for decades.
+typedef PCWSTR LPCWSTR; // The LP stands for "Long Pointer" which has been obsolete for decades.
// Common project types
//
-typedef _Return_type_success_( return >= 0 ) INT ERR;
-
+typedef _Return_type_success_( return >= 0 ) INT32 ERR;
//
// Limits
//
-const USHORT usMin = 0x0000;
-const USHORT usMax = 0xFFFF;
-const LONG lMin = 0x80000000;
-const LONG lMax = 0x7FFFFFFF;
+constexpr UINT16 usMin = 0x0000;
+constexpr UINT16 usMax = 0xFFFF;
+
+constexpr INT32 lMin = 0x80000000;
+constexpr INT32 lMax = 0x7FFFFFFF;
-const ULONG ulMin = 0x00000000;
-const ULONG ulMax = 0xFFFFFFFF;
+constexpr UINT32 ulMin = 0x00000000;
+constexpr UINT32 ulMax = 0xFFFFFFFF;
-const LONG64 llMin = 0x8000000000000000;
-const LONG64 llMax = 0x7FFFFFFFFFFFFFFF;
+constexpr INT64 llMin = 0x8000000000000000;
+constexpr INT64 llMax = 0x7FFFFFFFFFFFFFFF;
-const ULONG64 ullMin = 0x0000000000000000;
-const ULONG64 ullMax = 0xFFFFFFFFFFFFFFFF;
+constexpr UINT64 ullMin = 0x0000000000000000;
+constexpr UINT64 ullMax = 0xFFFFFFFFFFFFFFFF;
#if defined(_WIN64)
-const UNSIGNED_PTR upMin = ullMin;
-const UNSIGNED_PTR upMax = ullMax;
+const UNSIGNED_PTR upMin = 0x0000000000000000;
+const UNSIGNED_PTR upMax = 0xFFFFFFFFFFFFFFFF;
#else // !_WIN64
-const UNSIGNED_PTR upMin = ulMin;
-const UNSIGNED_PTR upMax = ulMax;
+const UNSIGNED_PTR upMin = 0x00000000;
+const UNSIGNED_PTR upMax = 0xFFFFFFFF;
#endif // _WIN64
-const QWORD bMax = 0xFF;
-const QWORD wMax = 0xFFFF;
-const QWORD dwMax = 0xFFFFFFFF;
-const QWORD qwMax = 0xFFFFFFFFFFFFFFFF;
+constexpr QWORD bMax = 0xFF;
+constexpr QWORD wMax = 0xFFFF;
+constexpr QWORD dwMax = 0xFFFFFFFF;
+constexpr QWORD qwMax = 0xFFFFFFFFFFFFFFFF;
+
+// Explicit numeric values were used to emphasize differences visually, but lets make sure the values used
+// match the expected symbolic values from standard headers.
+static_assert( usMin == 0 );
+static_assert( usMax == UINT16_MAX );
+static_assert( lMin == INT32_MIN );
+static_assert( lMax == INT32_MAX );
+static_assert( ulMin == 0 );
+static_assert( ulMax == UINT32_MAX );
+static_assert( llMin == INT64_MIN );
+static_assert( llMax == INT64_MAX );
+static_assert( ullMin == 0 );
+static_assert( ullMax == UINT64_MAX );
+static_assert( upMin == 0 );
+static_assert( upMax == UINTPTR_MAX );
+static_assert( bMax == UINT8_MAX );
+static_assert( wMax == UINT16_MAX );
+static_assert( dwMax == UINT32_MAX );
+static_assert( qwMax == UINT64_MAX );
+
//
// Declarative Defines
//
-#ifndef _MSC_VER
-
- // Only the Microsoft VC++ in some build environment has alternate calling conventions as default at play and
- // thus requires cdecl to be declared where we want the classic calling convention, so on we can just
- // define this to nothing on UNIX (as everything is implicitly __cdecl there).
- #define __cdecl
- #define __stdcall
-
-#endif // !_MSC_VER
-
-
+// This will go away to be replaced with static_assert
+#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
//
-// Map commonly used CRT like pseudo functions
+// Call type overrides
//
-#ifndef _MSC_VER
+#ifdef _MSC_VER
+
+ // None
- #define _stricmp strcasecmp
+#else // !_MSC_VER
-#endif // !_MSC_VER
+ // Only the Microsoft VC++ in some build environment has alternate calling conventions as default at play and
+ // thus requires cdecl to be declared where we want the classic calling convention, so on we can just
+ // define this to nothing elsewhere (such as GCC on Unix, as everything is implicitly __cdecl there).
+ #define __cdecl
+ #define __stdcall
+#endif
//
-// Basic "C operators"
+// Map commonly used CRT like pseudo functions and basic "C" operators
//
#ifdef _MSC_VER
-#define OffsetOf(s,m) (SIZE_T)&(((s *)0)->m)
-#else
-#define OffsetOf(s,m) __builtin_offsetof( s, m )
-#endif
-#define CONTAINING_RECORD(address, type, field) ((type *)( \
- (PCHAR)(address) - \
- (ULONG_PTR)(&((type *)0)->field)))
+ #define OffsetOf(s,m) (SIZE_T)&(((s *)0)->m)
+ // No need for _stricmp, it's defined by MSVC
+ // No need for _countof, it's defined by MSVC
+
+#else // !_MSC_VER
+
+ #define OffsetOf(s,m) __builtin_offsetof( s, m )
+ #define _stricmp strcasecmp
+ #define _countof(rg) ( sizeof(rg) / sizeof(rg[0]) )
-#ifdef _MSC_VER
-// No need - this set of operators (such as _countof()) is defined for MSVC tool set.
-#else
-#define _countof(rg) ( sizeof(rg) / sizeof(rg[0]) )
#endif
#define _cbrg(rg) ( _countof(rg) * sizeof(rg[0]) )
-
//
// Compiler warning control
//
@@ -315,21 +322,26 @@ const QWORD qwMax = 0xFFFFFFFFFFFFFFFF;
#pragma warning ( disable : 4786 ) // we allow huge symbol names
#ifdef DEBUG
- #else // DEBUG
+ // None
+ #else // !DEBUG
#pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
- #endif // !DEBUG
+ #endif
#define Unused( var ) ( var )
-#endif // _MSC_VER
+#else // !_MSC_VER
+
+ // None
+
+#endif
#if !defined(BEGIN_PRAGMA_OPTIMIZE_DISABLE)
-#define BEGIN_PRAGMA_OPTIMIZE_DISABLE(flags, bug, reason) \
- __pragma(optimize(flags, off))
-#define BEGIN_PRAGMA_OPTIMIZE_ENABLE(flags, bug, reason) \
- __pragma(optimize(flags, on))
-#define END_PRAGMA_OPTIMIZE() \
- __pragma(optimize("", on))
+ #define BEGIN_PRAGMA_OPTIMIZE_DISABLE(flags, bug, reason) \
+ __pragma(optimize(flags, off))
+ #define BEGIN_PRAGMA_OPTIMIZE_ENABLE(flags, bug, reason) \
+ __pragma(optimize(flags, on))
+ #define END_PRAGMA_OPTIMIZE() \
+ __pragma(optimize("", on))
#endif
diff --git a/dev/ese/published/inc/collection.hxx b/dev/ese/published/inc/collection.hxx
index da4ed934..c9977961 100644
--- a/dev/ese/published/inc/collection.hxx
+++ b/dev/ese/published/inc/collection.hxx
@@ -4451,6 +4451,9 @@ class CArray
void SetEntryDefault( const CEntry& entry );
ERR ErrSetEntry( const size_t ientry, const CEntry& entry );
+ ERR ErrAppendEntry( const CEntry& entry );
+ bool FRemoveLastEntry();
+ void Clear();
void SetEntry( const CEntry* const pentry, const CEntry& entry );
ERR ErrLoadEntries( const BYTE* const rgbData, const size_t cbData );
@@ -4687,6 +4690,42 @@ ErrSetEntry( const size_t ientry, const CEntry& entry )
return ERR::errSuccess;
}
+// grows the array by one element and sets that element to the value provided
+
+template< class CEntry >
+inline typename CArray< CEntry >::ERR CArray< CEntry >::
+ErrAppendEntry( const CEntry& entry )
+{
+ return ErrSetEntry( Size(), entry );
+}
+
+// removes the last entry of the array, returns false IFF the array is already empty
+
+template< class CEntry >
+inline typename bool CArray< CEntry >::
+FRemoveLastEntry()
+{
+ if ( Size() == 0 )
+ {
+ return false;
+ }
+
+ const ERR err = ErrSetSize( Size() - 1 );
+ COLLAssert( err == ERR::errSuccess );
+
+ return true;
+}
+
+// sets the array size to zero
+
+template< class CEntry >
+inline typename void CArray< CEntry >::
+Clear()
+{
+ const ERR err = ErrSetSize( 0 );
+ COLLAssert( err == ERR::errSuccess );
+}
+
// sets an existing entry of the array. WARNING: the array size and capacity
// are not adjusted accordingly, so this method is only supposed to be used
// to set existing elements.
@@ -7040,6 +7079,175 @@ inline T IrrPrev( T iCurrent, const size_t cRoundRobinBufferElements )
return ret;
}
+// *****************************************************
+// FixedArray helper class.
+// Use with an allocator of your choice to create a runtime fixed sized array.
+// For example, use with NoAlloc & _alloca to declare arrays on stack.
+//
+
+class NoAlloc
+{
+public:
+ // Lower-case to confirm with std::allocator
+ // Illegal to call allocate using this allocator (externally allocated)
+ // Legal to call deallocate, but does nothing
+ BYTE* allocate( std::size_t n ) = delete;
+ void deallocate( BYTE* p, std::size_t n ) {};
+};
+
+class HeapAllocator
+{
+public:
+ BYTE* allocate( std::size_t n ) { return new BYTE[ n ]; }
+ void deallocate( BYTE* pb, std::size_t n ) { delete[] pb; }
+};
+
+template
+class FixedArray
+{
+protected:
+ T* m_rgT = nullptr;
+ int m_cItems = 0;
+ bool m_fOwnsArray = false;
+
+public:
+ FixedArray() = default;
+ FixedArray( void* pv, int cItems, bool fOwnsArray = true ) :
+ m_rgT( reinterpret_cast( pv ) ),
+ m_cItems( cItems ),
+ m_fOwnsArray( fOwnsArray )
+ {
+ // Vectorized placement-new, i.e. new()[] is broken in the C++ standard
+ // because it can pad the placement pointer with an arbitrary number of bytes
+ // (e.g. vc pads it with some bytes keeping count of objects passed to new()[]).
+ // This leads to UB because after padding, the initialized objects overrun the allocated buffer.
+ // To avoid this, we have to loop and initialize each object individually, thus avoiding new()[].
+ if ( fOwnsArray )
+ {
+ for ( int i = 0; i < cItems; i++ )
+ {
+ new( &m_rgT[ i ] ) T{};
+ }
+ }
+ }
+
+ // Needed for the copy constructor.
+ template
+ friend class FixedArray;
+
+ // The copy contructor for this class allows copying from an array whose elements are the same type.
+ // The allocator type doesn't matter because ownership isn't transferred with the copy.
+ template
+ FixedArray( const FixedArray& rhs )
+ {
+ // Makes a copy, this means rhs stays intact.
+ // New object doesn't own the array.
+ m_rgT = rhs.m_rgT;
+ m_cItems = rhs.m_cItems;
+ m_fOwnsArray = false;
+ }
+
+ FixedArray( FixedArray&& rhs )
+ {
+ // Takes ownership of the array.
+ // rhs relinquishes control.
+ m_rgT = rhs.m_rgT;
+ m_cItems = rhs.m_cItems;
+ m_fOwnsArray = rhs.m_fOwnsArray;
+ rhs.m_rgT = NULL;
+ rhs.m_cItems = 0;
+ rhs.m_fOwnsArray = false;
+ }
+
+ // Copy assignment makes a copy without transferring ownership.
+ template
+ const FixedArray& operator=( const FixedArray& rhs )
+ {
+ Free();
+ m_rgT = rhs.m_rgT;
+ m_cItems = rhs.m_cItems;
+ m_fOwnsArray = false;
+ return *this;
+ }
+
+ // Move assignment takes ownership.
+ const FixedArray& operator= ( FixedArray&& rhs )
+ {
+ std::swap( m_rgT, rhs.m_rgT );
+ std::swap( m_cItems, rhs.m_cItems );
+ std::swap( m_fOwnsArray, rhs.m_fOwnsArray );
+ return *this;
+ }
+
+protected:
+ void Free()
+ {
+ if ( m_fOwnsArray )
+ {
+ for ( int i = 0; i < m_cItems; i++ )
+ {
+ m_rgT[ i ].~T();
+ }
+
+ TAlloc allocator;
+ allocator.deallocate( (BYTE*) m_rgT, sizeof( T ) * m_cItems );
+ }
+ }
+
+public:
+ ~FixedArray() { Free(); }
+ int CItems() const { return m_cItems; }
+ T* PrgT() { return m_rgT; }
+ const T* PrgT() const { return m_rgT; }
+ const T& operator[]( int i ) const { return m_rgT[ i ]; }
+ T& operator[]( int i ) { return m_rgT[ i ]; }
+ operator const T* ( ) const { return m_rgT; }
+ operator T* ( ) { return m_rgT; }
+ FixedArray Subarray( int iBegin ) const { return Subarray( iBegin, m_cItems ); }
+
+ // Implicit conversion to a FixedArray that doesn't own the array.
+ // Allows using FixedArray as a generic container for parameter passing.
+ operator FixedArray() const { return FixedArray( m_rgT, m_cItems, false ); }
+
+ // Returns the range [iBegin, iEnd).
+ // Retains ownership of the subarray items.
+ FixedArray Subarray( int iBegin, int iEnd ) const
+ {
+ Assert( iBegin >= 0 );
+ Assert( iEnd <= m_cItems );
+ Assert( iEnd >= iBegin );
+ return FixedArray( &m_rgT[ iBegin ], iEnd - iBegin, false );
+ }
+
+ template
+ void ForEach( TFunc func )
+ {
+ for ( int i = 0; i < m_cItems; i++ )
+ {
+ func( m_rgT[ i ] ); // TFunc takes T&
+ }
+ }
+
+ template
+ void ForEach( TFunc func ) const
+ {
+ for ( int i = 0; i < m_cItems; i++ )
+ {
+ func( m_rgT[ i ] ); // TFunc takes const T&
+ }
+ }
+
+ static FixedArray MakeArray( int citems )
+ {
+ TAlloc allocator;
+ BYTE* ptr = allocator.allocate( sizeof( T ) * citems );
+ return FixedArray( ptr, ptr != NULL ? citems : 0 );
+ }
+};
+
+template
+using FixedHeapArray = FixedArray;
+
NAMESPACE_END( COLL );
using namespace COLL;
diff --git a/dev/ese/published/inc/jethdr.w b/dev/ese/published/inc/jethdr.w
index de5806c6..25a45edb 100644
--- a/dev/ese/published/inc/jethdr.w
+++ b/dev/ese/published/inc/jethdr.w
@@ -66,34 +66,54 @@ extern "C" {
#define JET_API __stdcall
#define JET_NODSAPI __stdcall
-// end_PubEsent
-//
-// UNDONE: should we just remove this redefinition and
-// include basetsd.h (then typedef JET_API_PTR to ULONG_PTR)??
-//
-// begin_PubEsent
+#ifndef _JET_BASE_TYPES_DEFINED
+#define _JET_BASE_TYPES_DEFINED
+// Note the use of "long" rather than "int" for JET_INT32/JET_UINT32.
+// The JET_API has historically used the base type "long" for 32bit integral
+// types. While "int" and "long" are both 32bit integral types and coerce
+// back and forth and so may be used interchangably, "int *" and "long *" do
+// not. If the base type of the 32bit integral types were to change to
+// "int", existing client code could break and require casts for the pointer types.
+typedef char JET_INT8;
+typedef unsigned char JET_UINT8;
+typedef short JET_INT16;
+typedef unsigned short JET_UINT16;
+typedef long JET_INT32;
+typedef unsigned long JET_UINT32;
+typedef long long JET_INT64;
+typedef unsigned long long JET_UINT64;
+typedef unsigned char JET_BYTE;
+typedef void JET_VOID;
+typedef void * JET_PVOID;
+typedef const void * JET_PCVOID;
+typedef char JET_CHAR;
+#if !defined(_NATIVE_WCHAR_T_DEFINED)
+typedef unsigned short JET_WCHAR;
+#else
+typedef wchar_t JET_WCHAR;
+#endif
+#endif // _JET_BASE_TYPES_DEFINED
+
#if defined(_WIN64)
- typedef unsigned __int64 JET_API_PTR;
-#elif !defined(__midl) && (defined(_X86_) || defined(_M_IX86))
- typedef __w64 unsigned long JET_API_PTR;
+ typedef JET_UINT64 JET_API_PTR;
#else
- typedef unsigned long JET_API_PTR;
+ typedef JET_UINT32 JET_API_PTR;
#endif
-typedef _Return_type_success_( return >= 0 ) long JET_ERR;
+typedef _Return_type_success_( return >= 0 ) JET_INT32 JET_ERR;
// end_PubEsent
#if ( JET_VERSION >= 0x0A01 )
-typedef unsigned long JET_ENGINEFORMATVERSION; /* efv - engine format version specification */
+typedef JET_UINT32 JET_ENGINEFORMATVERSION; // efv - engine format version specification
#endif // JET_VERSION >= 0x0A01
// begin_PubEsent
-typedef JET_API_PTR JET_HANDLE; /* backup file handle */
-typedef JET_API_PTR JET_INSTANCE; /* Instance Identifier */
-typedef JET_API_PTR JET_SESID; /* Session Identifier */
-typedef JET_API_PTR JET_TABLEID; /* Table Identifier */
+typedef JET_API_PTR JET_HANDLE; // backup file handle
+typedef JET_API_PTR JET_INSTANCE; // Instance Identifier
+typedef JET_API_PTR JET_SESID; // Session Identifier
+typedef JET_API_PTR JET_TABLEID; // Table Identifier
#if ( JET_VERSION >= 0x0501 )
-typedef JET_API_PTR JET_LS; /* Local Storage */
+typedef JET_API_PTR JET_LS; // Local Storage
#endif // JET_VERSION >= 0x0501
// end_PubEsent
#if ( JET_VERSION >= 0x0601 )
@@ -101,37 +121,37 @@ typedef JET_API_PTR JET_HISTO;
#endif // JET_VERSION >= 0x0601
// begin_PubEsent
-typedef unsigned long JET_COLUMNID; /* Column Identifier */
+typedef JET_UINT32 JET_COLUMNID; // Column Identifier
typedef struct tagJET_INDEXID
{
- unsigned long cbStruct;
- unsigned char rgbIndexId[sizeof(JET_API_PTR)+sizeof(unsigned long)+sizeof(unsigned long)];
+ JET_UINT32 cbStruct;
+ JET_BYTE rgbIndexId[sizeof(JET_API_PTR)+sizeof(JET_UINT32)+sizeof(JET_UINT32)];
} JET_INDEXID;
-typedef unsigned long JET_DBID; /* Database Identifier */
-typedef unsigned long JET_OBJTYP; /* Object Type */
-typedef unsigned long JET_COLTYP; /* Column Type */
-typedef unsigned long JET_GRBIT; /* Group of Bits */
+typedef JET_UINT32 JET_DBID; // Database Identifier
+typedef JET_UINT32 JET_OBJTYP; // Object Type
+typedef JET_UINT32 JET_COLTYP; // Column Type
+typedef JET_UINT32 JET_GRBIT; // Group of Bits
-typedef unsigned long JET_SNP; /* Status Notification Process */
-typedef unsigned long JET_SNT; /* Status Notification Type */
+typedef JET_UINT32 JET_SNP; // Status Notification Process
+typedef JET_UINT32 JET_SNT; // Status Notification Type
// end_PubEsent
-typedef unsigned long JET_SNC; /* Status Notification Code */
+typedef JET_UINT32 JET_SNC; // Status Notification Code
// begin_PubEsent
-typedef double JET_DATESERIAL; /* JET_coltypDateTime format */
+typedef double JET_DATESERIAL; // JET_coltypDateTime format
// end_PubEsent
-typedef unsigned long JET_DLLID; /* ID of DLL for hook functions */
+typedef JET_UINT32 JET_DLLID; // ID of DLL for hook functions
// begin_PubEsent
#if ( JET_VERSION >= 0x0501 )
-typedef unsigned long JET_CBTYP; /* Callback Types */
+typedef JET_UINT32 JET_CBTYP; // Callback Types
#endif // JET_VERSION >= 0x0501
-typedef JET_ERR (JET_API *JET_PFNSTATUS)(
- _In_ JET_SESID sesid,
- _In_ JET_SNP snp,
- _In_ JET_SNT snt,
- _In_opt_ void * pv );
+typedef JET_ERR (JET_API * JET_PFNSTATUS)(
+ _In_ JET_SESID sesid,
+ _In_ JET_SNP snp,
+ _In_ JET_SNT snt,
+ _In_opt_ JET_PVOID pv );
// end_PubEsent
@@ -141,37 +161,32 @@ typedef JET_ERR (JET_API *JET_PFNSTATUS)(
// it has a user-provided context and eliminates the unused sesid
// parameter.
typedef JET_ERR (JET_API * JET_PFNINITCALLBACK)(
- _In_ JET_SNP snp,
- _In_ JET_SNT snt,
- _In_opt_ void * pv, // depends on the snp, snt
- _In_opt_ void * pvContext ); // provided in JetInit4
+ _In_ JET_SNP snp,
+ _In_ JET_SNT snt,
+ _In_opt_ JET_PVOID pv, // depends on the snp, snt
+ _In_opt_ JET_PVOID pvContext ); // provided in JetInit4
#endif // JET_VERSION >= 0x0A01
// begin_PubEsent
-#if !defined(_NATIVE_WCHAR_T_DEFINED)
-typedef unsigned short WCHAR;
-#else
-typedef wchar_t WCHAR;
-#endif
+typedef _Null_terminated_ JET_CHAR * JET_PSTR; // ASCII string (char *) null terminated
+typedef _Null_terminated_ const JET_CHAR * JET_PCSTR; // const ASCII string (char *) null terminated
+typedef _Null_terminated_ JET_WCHAR * JET_PWSTR; // Unicode string (wchar_t *) null terminated
+typedef _Null_terminated_ const JET_WCHAR * JET_PCWSTR; // const Unicode string (wchar_t *) null terminated
-typedef _Null_terminated_ char * JET_PSTR; /* ASCII string (char *) null terminated */
-typedef _Null_terminated_ const char * JET_PCSTR; /* const ASCII string (char *) null terminated */
-typedef _Null_terminated_ WCHAR * JET_PWSTR; /* Unicode string (char *) null terminated */
-typedef _Null_terminated_ const WCHAR * JET_PCWSTR; /* const Unicode string (char *) null terminated */
typedef struct
{
- char *szDatabaseName;
- char *szNewDatabaseName;
-} JET_RSTMAP_A; /* restore map */
+ JET_PSTR szDatabaseName;
+ JET_PSTR szNewDatabaseName;
+} JET_RSTMAP_A; // restore map
typedef struct
{
- WCHAR *szDatabaseName;
- WCHAR *szNewDatabaseName;
-} JET_RSTMAP_W; /* restore map */
+ JET_PWSTR szDatabaseName;
+ JET_PWSTR szNewDatabaseName;
+} JET_RSTMAP_W; // restore map
#ifdef JET_UNICODE
#define JET_RSTMAP JET_RSTMAP_W
@@ -185,32 +200,32 @@ typedef struct
typedef struct tagJET_SETDBPARAM
{
- unsigned long dbparamid; // One of the JET_dbparams.
+ JET_UINT32 dbparamid; // One of the JET_dbparams.
- _Field_size_bytes_( cbParam ) void * pvParam; // Address of the value of the parameter. Note that even for integral types, a valid
- // memory location must be passed, as opposed to the numerical value cast to a void*.
+ _Field_size_bytes_( cbParam ) JET_PVOID pvParam; // Address of the value of the parameter. Note that even for integral types, a valid
+ // memory location must be passed, as opposed to the numerical value cast to a PVOID.
- unsigned long cbParam; // The size of the data, in bytes, pointed to by pvParam.
+ JET_UINT32 cbParam; // The size of the data, in bytes, pointed to by pvParam.
} JET_SETDBPARAM;
typedef struct
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szDatabaseName; // (optional) original database path
- char *szNewDatabaseName; // new database path
- _Field_size_opt_( csetdbparam ) JET_SETDBPARAM *rgsetdbparam; // (optional) array of database parameters
- unsigned long csetdbparam; // number of elements in rgsetdbparam
- JET_GRBIT grbit; // recovery options
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szDatabaseName; // (optional) original database path
+ JET_PSTR szNewDatabaseName; // new database path
+ _Field_size_opt_( csetdbparam ) JET_SETDBPARAM * rgsetdbparam; // (optional) array of database parameters
+ JET_UINT32 csetdbparam; // number of elements in rgsetdbparam
+ JET_GRBIT grbit; // recovery options
} JET_RSTMAP2_A;
typedef struct
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szDatabaseName; // (optional) original database path
- WCHAR *szNewDatabaseName; // new database path
- _Field_size_opt_( csetdbparam ) JET_SETDBPARAM *rgsetdbparam; // (optional) array of database parameters
- unsigned long csetdbparam; // number of elements in rgsetdbparam
- JET_GRBIT grbit; // recovery options
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szDatabaseName; // (optional) original database path
+ JET_PWSTR szNewDatabaseName; // new database path
+ _Field_size_opt_( csetdbparam ) JET_SETDBPARAM * rgsetdbparam; // (optional) array of database parameters
+ JET_UINT32 csetdbparam; // number of elements in rgsetdbparam
+ JET_GRBIT grbit; // recovery options
} JET_RSTMAP2_W;
#ifdef JET_UNICODE
@@ -227,26 +242,26 @@ typedef struct
typedef struct tagCONVERT_A
{
- char *szOldDll;
+ JET_PSTR szOldDll;
union
{
- unsigned long fFlags;
+ JET_UINT32 fFlags;
struct
{
- unsigned long fSchemaChangesOnly:1;
+ JET_UINT32 fSchemaChangesOnly:1;
};
};
} JET_CONVERT_A;
typedef struct tagCONVERT_W
{
- WCHAR *szOldDll;
+ JET_PWSTR szOldDll;
union
{
- unsigned long fFlags;
+ JET_UINT32 fFlags;
struct
{
- unsigned long fSchemaChangesOnly:1;
+ JET_UINT32 fSchemaChangesOnly:1;
};
};
} JET_CONVERT_W;
@@ -310,7 +325,7 @@ typedef enum
typedef struct tagDBUTIL_A
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_SESID sesid;
JET_DBID dbid;
@@ -329,51 +344,51 @@ typedef struct tagDBUTIL_A
// legacy elements
struct
{
- char *szDatabase;
- char *szSLV_ObsoleteAndUnused; // No longer used. Left in to preserve the subsequent values;
- char *szBackup;
- const char *szTable;
- const char *szIndex;
- char *szIntegPrefix;
+ JET_PSTR szDatabase;
+ JET_PSTR szSLV_ObsoleteAndUnused; // No longer used. Left in to preserve the subsequent values;
+ JET_PSTR szBackup;
+ JET_PCSTR szTable;
+ JET_PCSTR szIndex;
+ JET_PSTR szIntegPrefix;
- long pgno;
- long iline;
+ JET_INT32 pgno;
+ JET_INT32 iline;
- long lGeneration;
- long isec;
- long ib;
+ JET_INT32 lGeneration;
+ JET_INT32 isec;
+ JET_INT32 ib;
- long cRetry;
+ JET_INT32 cRetry;
- void * pfnCallback;
- void * pvCallback;
+ JET_PVOID pfnCallback;
+ JET_PVOID pvCallback;
};
// ChecksumLogFromMemory
struct
{
- char *szLog; // Name of the Log file
- char *szBase; // Base name used e.g. "edb" or "E01"
- void *pvBuffer; // Pointer to buffer containing the log
- long cbBuffer; // Length of buffer
+ JET_PSTR szLog; // Name of the Log file
+ JET_PSTR szBase; // Base name used e.g. "edb" or "E01"
+ JET_PVOID pvBuffer; // Pointer to buffer containing the log
+ JET_INT32 cbBuffer; // Length of buffer
} checksumlogfrommemory;
// opDBUTILDumpSpaceCategory
struct
{
- char *szDatabase; // Database from which to dump the space category of pages.
- unsigned long pgnoFirst; // First page to dump the category for. The first page in the database is 1.
- unsigned long pgnoLast; // Last page to dump the category for. The last page in the database can be passed in as (unsigned long)-1.
- void *pfnSpaceCatCallback; // Callback to receive each page's category (JET_SPCATCALLBACK).
- void *pvContext; // General purpose context which is passed back to the client callback (pfnSpaceCatCallback).
+ JET_PSTR szDatabase; // Database from which to dump the space category of pages.
+ JET_UINT32 pgnoFirst; // First page to dump the category for. The first page in the database is 1.
+ JET_UINT32 pgnoLast; // Last page to dump the category for. The last page in the database can be passed in as (JET_UINT32)-1.
+ JET_PVOID pfnSpaceCatCallback; // Callback to receive each page's category (JET_SPCATCALLBACK).
+ JET_PVOID pvContext; // General purpose context which is passed back to the client callback (pfnSpaceCatCallback).
} spcatOptions;
// opDBUTILDumpRBS
struct
{
- char *szDatabase; // Database from which to dump the space category of pages.
- unsigned long pgnoFirst; // First page to dump the category for. The first page in the database is 1.
- unsigned long pgnoLast; // Last page to dump the category for. The last page in the database can be passed in as (unsigned long)-1.
+ JET_PSTR szDatabase; // Database from which to dump the space category of pages.
+ JET_UINT32 pgnoFirst; // First page to dump the category for. The first page in the database is 1.
+ JET_UINT32 pgnoLast; // Last page to dump the category for. The last page in the database can be passed in as (JET_UINT32)-1.
} rbsOptions;
};
@@ -382,7 +397,7 @@ typedef struct tagDBUTIL_A
typedef struct tagDBUTIL_W
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_SESID sesid;
JET_DBID dbid;
@@ -401,51 +416,51 @@ typedef struct tagDBUTIL_W
// legacy elements
struct
{
- WCHAR *szDatabase;
- WCHAR *szSLV_ObsoleteAndUnused; // No longer used. Left in to preserve the subsequent values;
- WCHAR *szBackup;
- const WCHAR *szTable;
- const WCHAR *szIndex;
- WCHAR *szIntegPrefix;
+ JET_PWSTR szDatabase;
+ JET_PWSTR szSLV_ObsoleteAndUnused; // No longer used. Left in to preserve the subsequent values;
+ JET_PWSTR szBackup;
+ JET_PCWSTR szTable;
+ JET_PCWSTR szIndex;
+ JET_PWSTR szIntegPrefix;
- long pgno;
- long iline;
+ JET_INT32 pgno;
+ JET_INT32 iline;
- long lGeneration;
- long isec;
- long ib;
+ JET_INT32 lGeneration;
+ JET_INT32 isec;
+ JET_INT32 ib;
- long cRetry;
+ JET_INT32 cRetry;
- void *pfnCallback;
- void *pvCallback;
+ JET_PVOID pfnCallback;
+ JET_PVOID pvCallback;
};
// ChecksumLogFromMemory
struct
{
- WCHAR *szLog; // Name of the Log file
- WCHAR *szBase; // Base name used e.g. "edb" or "E01"
- void *pvBuffer; // Pointer to buffer containing the log
- long cbBuffer; // Length of buffer
+ JET_PWSTR szLog; // Name of the Log file
+ JET_PWSTR szBase; // Base name used e.g. "edb" or "E01"
+ JET_PVOID pvBuffer; // Pointer to buffer containing the log
+ JET_INT32 cbBuffer; // Length of buffer
} checksumlogfrommemory;
// opDBUTILDumpSpaceCategory
struct
{
- WCHAR *szDatabase; // Database from which to dump the space category of pages.
- unsigned long pgnoFirst; // First page to dump the category for. The first page in the database is 1.
- unsigned long pgnoLast; // Last page to dump the category for. The last page in the database can be passed in as (unsigned long)-1.
- void *pfnSpaceCatCallback; // Callback to receive each page's category (JET_SPCATCALLBACK).
- void *pvContext; // General purpose context.
+ JET_PWSTR szDatabase; // Database from which to dump the space category of pages.
+ JET_UINT32 pgnoFirst; // First page to dump the category for. The first page in the database is 1.
+ JET_UINT32 pgnoLast; // Last page to dump the category for. The last page in the database can be passed in as (JET_UINT32)-1.
+ JET_PVOID pfnSpaceCatCallback; // Callback to receive each page's category (JET_SPCATCALLBACK).
+ JET_PVOID pvContext; // General purpose context.
} spcatOptions;
// opDBUTILDumpRBS
struct
{
- WCHAR *szDatabase; // Database from which to dump the space category of pages.
- unsigned long pgnoFirst; // First page to dump the category for. The first page in the database is 1.
- unsigned long pgnoLast; // Last page to dump the category for. The last page in the database can be passed in as (unsigned long)-1.
+ JET_PWSTR szDatabase; // Database from which to dump the space category of pages.
+ JET_UINT32 pgnoFirst; // First page to dump the category for. The first page in the database is 1.
+ JET_UINT32 pgnoLast; // Last page to dump the category for. The last page in the database can be passed in as (JET_UINT32)-1.
} rbsOptions;
};
@@ -490,13 +505,17 @@ typedef enum
} SpaceCategoryFlags;
// Callback used by opDBUTILDumpSpaceCategory to return page space categories.
-typedef void (JET_API *JET_SPCATCALLBACK)( _In_ const unsigned long pgno, _In_ const unsigned long objid, _In_ const SpaceCategoryFlags spcatf, _In_opt_ void* const pvContext );
+typedef JET_VOID (JET_API * JET_SPCATCALLBACK)(
+ _In_ const JET_UINT32 pgno,
+ _In_ const JET_UINT32 objid,
+ _In_ const SpaceCategoryFlags spcatf,
+ _In_opt_ const JET_PVOID pvContext );
#endif // JET_VERSION >= 0x0A01
// DBUTIL_OP op = opDBUTILDumpSpace
//
#define JET_bitDBUtilSpaceInfoBasicCatalog 0x00000001
-#define JET_bitDBUtilSpaceInfoSpaceTrees 0x00000002
+#define JET_bitDBUtilSpaceInfoSpaceTrees 0x00000002
#define JET_bitDBUtilSpaceInfoParentOfLeaf 0x00000004
#define JET_bitDBUtilSpaceInfoFullWalk 0x00000008
// This command also utilizes this option:
@@ -763,15 +782,15 @@ typedef void (JET_API *JET_SPCATCALLBACK)( _In_ const unsigned long pgno, _In_ c
/* Callback-function prototype */
-typedef JET_ERR (JET_API *JET_CALLBACK)(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_TABLEID tableid,
- _In_ JET_CBTYP cbtyp,
- _Inout_opt_ void * pvArg1,
- _Inout_opt_ void * pvArg2,
- _In_opt_ void * pvContext,
- _In_ JET_API_PTR ulUnused );
+typedef JET_ERR (JET_API * JET_CALLBACK)(
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_TABLEID tableid,
+ _In_ JET_CBTYP cbtyp,
+ _Inout_opt_ JET_PVOID pvArg1,
+ _Inout_opt_ JET_PVOID pvArg2,
+ _In_opt_ JET_PVOID pvContext,
+ _In_ JET_API_PTR ulUnused );
#endif // JET_VERSION >= 0x0501
// end_PubEsent
@@ -795,18 +814,18 @@ typedef JET_ERR (JET_API *JET_CALLBACK)(
//
// currently UNSUPPORTED
//
-typedef JET_ERR (JET_API *JET_ABORTRETRYFAILCALLBACK_A)(
- _In_ char * szFile,
- _In_ unsigned long Offset,
- _In_ unsigned long OffsetHigh,
- _In_ unsigned long Length,
+typedef JET_ERR (JET_API * JET_ABORTRETRYFAILCALLBACK_A)(
+ _In_ JET_PSTR szFile,
+ _In_ JET_UINT32 Offset,
+ _In_ JET_UINT32 OffsetHigh,
+ _In_ JET_UINT32 Length,
_In_ JET_ERR err );
-typedef JET_ERR (JET_API *JET_ABORTRETRYFAILCALLBACK_W)(
- _In_ WCHAR * szFile,
- _In_ unsigned long Offset,
- _In_ unsigned long OffsetHigh,
- _In_ unsigned long Length,
+typedef JET_ERR (JET_API * JET_ABORTRETRYFAILCALLBACK_W)(
+ _In_ JET_PWSTR szFile,
+ _In_ JET_UINT32 Offset,
+ _In_ JET_UINT32 OffsetHigh,
+ _In_ JET_UINT32 Length,
_In_ JET_ERR err );
#ifdef JET_UNICODE
@@ -899,12 +918,12 @@ typedef enum
//
// tracing callbacks
//
-typedef void (JET_API *JET_PFNTRACEEMIT)(
+typedef JET_VOID (JET_API * JET_PFNTRACEEMIT)(
_In_ const JET_TRACETAG tag,
_In_ JET_PCSTR szPrefix,
_In_ JET_PCSTR szTrace,
_In_ const JET_API_PTR ul );
-typedef void (JET_API *JET_PFNTRACEREGISTER)(
+typedef JET_VOID (JET_API * JET_PFNTRACEREGISTER)(
_In_ const JET_TRACETAG tag,
_In_ JET_PCSTR szDesc,
_Out_ JET_API_PTR * pul );
@@ -938,10 +957,10 @@ typedef enum
#if ( JET_VERSION >= 0x0600 )
typedef struct JET_SESSIONINFO
{
- unsigned long ulTrxBegin0;
- unsigned long ulTrxLevel;
- unsigned long ulProcid;
- unsigned long ulFlags;
+ JET_UINT32 ulTrxBegin0;
+ JET_UINT32 ulTrxLevel;
+ JET_UINT32 ulProcid;
+ JET_UINT32 ulFlags;
JET_API_PTR ulTrxContext;
} JET_SESSIONINFO;
#endif // JET_VERSION >= 0x0600
@@ -949,46 +968,46 @@ typedef struct JET_SESSIONINFO
/* Status Notification Structures */
-typedef struct /* Status Notification Progress */
+typedef struct // Status Notification Progress
{
- unsigned long cbStruct; /* Size of this structure */
- unsigned long cunitDone; /* Number of units of work completed */
- unsigned long cunitTotal; /* Total number of units of work */
+ JET_UINT32 cbStruct; // Size of this structure
+ JET_UINT32 cunitDone; // Number of units of work completed
+ JET_UINT32 cunitTotal; // Total number of units of work
} JET_SNPROG;
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
- unsigned long cbFilesizeLow; // file's current size (low DWORD)
- unsigned long cbFilesizeHigh; // file's current size (high DWORD)
+ JET_UINT32 cbFilesizeLow; // file's current size (low DWORD)
+ JET_UINT32 cbFilesizeHigh; // file's current size (high DWORD)
- unsigned long cbFreeSpaceRequiredLow; // estimate of free disk space required for in-place upgrade (low DWORD)
- unsigned long cbFreeSpaceRequiredHigh;// estimate of free disk space required for in-place upgrade (high DWORD)
+ JET_UINT32 cbFreeSpaceRequiredLow; // estimate of free disk space required for in-place upgrade (low DWORD)
+ JET_UINT32 cbFreeSpaceRequiredHigh;// estimate of free disk space required for in-place upgrade (high DWORD)
- unsigned long csecToUpgrade; // estimate of time required, in seconds, for upgrade
+ JET_UINT32 csecToUpgrade; // estimate of time required, in seconds, for upgrade
union
{
- unsigned long ulFlags;
+ JET_UINT32 ulFlags;
struct
{
- unsigned long fUpgradable:1;
- unsigned long fAlreadyUpgraded:1;
+ JET_UINT32 fUpgradable:1;
+ JET_UINT32 fAlreadyUpgraded:1;
};
};
} JET_DBINFOUPGRADE;
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_OBJTYP objtyp;
JET_DATESERIAL dtCreate; // Deprecated.
JET_DATESERIAL dtUpdate; // Deprecated.
JET_GRBIT grbit;
- unsigned long flags;
- unsigned long cRecord;
- unsigned long cPage;
+ JET_UINT32 flags;
+ JET_UINT32 cRecord;
+ JET_UINT32 cPage;
} JET_OBJECTINFO;
/* The following flags appear in the grbit field above */
@@ -1014,9 +1033,9 @@ typedef struct
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_TABLEID tableid;
- unsigned long cRecord;
+ JET_UINT32 cRecord;
JET_COLUMNID columnidcontainername;
JET_COLUMNID columnidobjectname;
JET_COLUMNID columnidobjtyp;
@@ -1024,17 +1043,17 @@ typedef struct
JET_COLUMNID columniddtUpdate; // XXX -- to be deleted
JET_COLUMNID columnidgrbit;
JET_COLUMNID columnidflags;
- JET_COLUMNID columnidcRecord; /* Level 2 info */
- JET_COLUMNID columnidcPage; /* Level 2 info */
+ JET_COLUMNID columnidcRecord; // Level 2 info
+ JET_COLUMNID columnidcPage; // Level 2 info
} JET_OBJECTLIST;
#define cObjectInfoCols 9
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_TABLEID tableid;
- unsigned long cRecord;
+ JET_UINT32 cRecord;
JET_COLUMNID columnidPresentationOrder;
JET_COLUMNID columnidcolumnname;
JET_COLUMNID columnidcolumnid;
@@ -1055,47 +1074,47 @@ typedef struct
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_COLUMNID columnid;
JET_COLTYP coltyp;
- unsigned short wCountry; // sepcifies the country/region for the column definition
- unsigned short langid;
- unsigned short cp;
- unsigned short wCollate; /* Must be 0 */
- unsigned long cbMax;
+ JET_UINT16 wCountry; // sepcifies the country/region for the column definition
+ JET_UINT16 langid;
+ JET_UINT16 cp;
+ JET_UINT16 wCollate; // Must be 0
+ JET_UINT32 cbMax;
JET_GRBIT grbit;
} JET_COLUMNDEF;
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_COLUMNID columnid;
JET_COLTYP coltyp;
- unsigned short wCountry; // specifies the columnid for the country/region field
- unsigned short langid;
- unsigned short cp;
- unsigned short wFiller; /* Must be 0 */
- unsigned long cbMax;
+ JET_UINT16 wCountry; // specifies the columnid for the country/region field
+ JET_UINT16 langid;
+ JET_UINT16 cp;
+ JET_UINT16 wFiller; // Must be 0
+ JET_UINT32 cbMax;
JET_GRBIT grbit;
- char szBaseTableName[256];
- char szBaseColumnName[256];
+ JET_CHAR szBaseTableName[256];
+ JET_CHAR szBaseColumnName[256];
} JET_COLUMNBASE_A;
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_COLUMNID columnid;
JET_COLTYP coltyp;
- unsigned short wCountry; // specifies the columnid for the country/region field
- unsigned short langid;
- unsigned short cp;
- unsigned short wFiller; /* Must be 0 */
- unsigned long cbMax;
+ JET_UINT16 wCountry; // specifies the columnid for the country/region field
+ JET_UINT16 langid;
+ JET_UINT16 cp;
+ JET_UINT16 wFiller; // Must be 0
+ JET_UINT32 cbMax;
JET_GRBIT grbit;
- WCHAR szBaseTableName[256];
- WCHAR szBaseColumnName[256];
+ JET_WCHAR szBaseTableName[256];
+ JET_WCHAR szBaseColumnName[256];
} JET_COLUMNBASE_W;
@@ -1108,9 +1127,9 @@ typedef struct
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_TABLEID tableid;
- unsigned long cRecord;
+ JET_UINT32 cRecord;
JET_COLUMNID columnidindexname;
JET_COLUMNID columnidgrbitIndex;
JET_COLUMNID columnidcKey;
@@ -1134,28 +1153,28 @@ typedef struct
typedef struct tag_JET_COLUMNCREATE_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szColumnName; // column name
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szColumnName; // column name
JET_COLTYP coltyp; // column type
- unsigned long cbMax; // the maximum length of this column (only relevant for binary and text columns)
+ JET_UINT32 cbMax; // the maximum length of this column (only relevant for binary and text columns)
JET_GRBIT grbit; // column options
- void *pvDefault; // default value (NULL if none)
- unsigned long cbDefault; // length of default value
- unsigned long cp; // code page (for text columns only)
+ JET_PVOID pvDefault; // default value (NULL if none)
+ JET_UINT32 cbDefault; // length of default value
+ JET_UINT32 cp; // code page (for text columns only)
JET_COLUMNID columnid; // returned column id
JET_ERR err; // returned error code
} JET_COLUMNCREATE_A;
typedef struct tag_JET_COLUMNCREATE_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szColumnName; // column name
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szColumnName; // column name
JET_COLTYP coltyp; // column type
- unsigned long cbMax; // the maximum length of this column (only relevant for binary and text columns)
+ JET_UINT32 cbMax; // the maximum length of this column (only relevant for binary and text columns)
JET_GRBIT grbit; // column options
- void *pvDefault; // default value (NULL if none)
- unsigned long cbDefault; // length of default value
- unsigned long cp; // code page (for text columns only)
+ JET_PVOID pvDefault; // default value (NULL if none)
+ JET_UINT32 cbDefault; // length of default value
+ JET_UINT32 cp; // code page (for text columns only)
JET_COLUMNID columnid; // returned column id
JET_ERR err; // returned error code
} JET_COLUMNCREATE_W;
@@ -1172,18 +1191,18 @@ typedef struct tag_JET_COLUMNCREATE_W
typedef struct tag_JET_USERDEFINEDDEFAULT_A
{
- char * szCallback;
- unsigned char * pbUserData;
- unsigned long cbUserData;
- char * szDependantColumns;
+ JET_PSTR szCallback;
+ JET_BYTE * pbUserData;
+ JET_UINT32 cbUserData;
+ JET_PSTR szDependantColumns;
} JET_USERDEFINEDDEFAULT_A;
typedef struct tag_JET_USERDEFINEDDEFAULT_W
{
- WCHAR * szCallback;
- unsigned char * pbUserData;
- unsigned long cbUserData;
- WCHAR * szDependantColumns;
+ JET_PWSTR szCallback;
+ JET_BYTE * pbUserData;
+ JET_UINT32 cbUserData;
+ JET_PWSTR szDependantColumns;
} JET_USERDEFINEDDEFAULT_W;
#ifdef JET_UNICODE
@@ -1196,15 +1215,15 @@ typedef struct tag_JET_USERDEFINEDDEFAULT_W
typedef struct tagJET_CONDITIONALCOLUMN_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szColumnName; // column that we are conditionally indexed on
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szColumnName; // column that we are conditionally indexed on
JET_GRBIT grbit; // conditional column options
} JET_CONDITIONALCOLUMN_A;
typedef struct tagJET_CONDITIONALCOLUMN_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szColumnName; // column that we are conditionally indexed on
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szColumnName; // column that we are conditionally indexed on
JET_GRBIT grbit; // conditional column options
} JET_CONDITIONALCOLUMN_W;
@@ -1216,27 +1235,27 @@ typedef struct tagJET_CONDITIONALCOLUMN_W
typedef struct tagJET_UNICODEINDEX
{
- unsigned long lcid;
- unsigned long dwMapFlags;
+ JET_UINT32 lcid;
+ JET_UINT32 dwMapFlags;
} JET_UNICODEINDEX;
#if ( JET_VERSION >= 0x0602 )
typedef struct tagJET_UNICODEINDEX2
{
- _Field_z_ WCHAR *szLocaleName;
- unsigned long dwMapFlags;
+ _Field_z_ JET_PWSTR szLocaleName;
+ JET_UINT32 dwMapFlags;
} JET_UNICODEINDEX2;
#endif //JET_VERSION >= 0x0602
#if ( JET_VERSION >= 0x0502 )
typedef struct tagJET_TUPLELIMITS
{
- unsigned long chLengthMin;
- unsigned long chLengthMax;
- unsigned long chToIndexMax;
+ JET_UINT32 chLengthMin;
+ JET_UINT32 chLengthMax;
+ JET_UINT32 chToIndexMax;
#if ( JET_VERSION >= 0x0600 )
- unsigned long cchIncrement;
- unsigned long ichStart;
+ JET_UINT32 cchIncrement;
+ JET_UINT32 ichStart;
#endif // JET_VERSION >= 0x0600
} JET_TUPLELIMITS;
#endif // JET_VERSION >= 0x0502
@@ -1246,9 +1265,9 @@ typedef struct tagJET_TUPLELIMITS
// table, index, or the internal long values tree.
typedef struct tagJET_SPACEHINTS
{
- unsigned long cbStruct; // size of this structure
- unsigned long ulInitialDensity; // density at (append) layout.
- unsigned long cbInitial; // initial size (in bytes).
+ JET_UINT32 cbStruct; // size of this structure
+ JET_UINT32 ulInitialDensity; // density at (append) layout.
+ JET_UINT32 cbInitial; // initial size (in bytes).
JET_GRBIT grbit; // Combination of one or more flags from
// JET_bitSpaceHints* flags
@@ -1256,11 +1275,11 @@ typedef struct tagJET_SPACEHINTS
// JET_bitRetrieveHints* flags
// JET_bitUpdateHints* flags
// JET_bitDeleteHints* flags
- unsigned long ulMaintDensity; // density to maintain at.
- unsigned long ulGrowth; // percent growth from:
+ JET_UINT32 ulMaintDensity; // density to maintain at.
+ JET_UINT32 ulGrowth; // percent growth from:
// last growth or initial size (possibly rounded to nearest native JET allocation size).
- unsigned long cbMinExtent; // This overrides ulGrowth if too small.
- unsigned long cbMaxExtent; // This caps ulGrowth.
+ JET_UINT32 cbMinExtent; // This overrides ulGrowth if too small.
+ JET_UINT32 cbMaxExtent; // This caps ulGrowth.
} JET_SPACEHINTS;
#endif // JET_VERSION >= 0x0601
@@ -1270,58 +1289,58 @@ typedef struct tagJET_SPACEHINTS
// was used (backward compatibility).
typedef struct tagJET_INDEXCREATEOLD_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szIndexName; // index name
- char *szKey; // index key definition
- unsigned long cbKey; // size of key definition in szKey
- JET_GRBIT grbit; // index options
- unsigned long ulDensity; // index density
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szIndexName; // index name
+ JET_PSTR szKey; // index key definition
+ JET_UINT32 cbKey; // size of key definition in szKey
+ JET_GRBIT grbit; // index options
+ JET_UINT32 ulDensity; // index density
union
{
- unsigned long lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
- JET_UNICODEINDEX *pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
+ JET_UINT32 lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
+ JET_UNICODEINDEX * pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
};
union
{
- unsigned long cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
+ JET_UINT32 cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
#if ( JET_VERSION >= 0x0502 )
- JET_TUPLELIMITS *ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
+ JET_TUPLELIMITS * ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
#endif // ! JET_VERSION >= 0x0502
};
- JET_CONDITIONALCOLUMN_A *rgconditionalcolumn; // pointer to conditional column structure
- unsigned long cConditionalColumn; // number of conditional columns
- JET_ERR err; // returned error code
+ JET_CONDITIONALCOLUMN_A * rgconditionalcolumn; // pointer to conditional column structure
+ JET_UINT32 cConditionalColumn; // number of conditional columns
+ JET_ERR err; // returned error code
} JET_INDEXCREATEOLD_A;
typedef struct tagJET_INDEXCREATEOLD_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szIndexName; // index name
- WCHAR *szKey; // index key definition
- unsigned long cbKey; // size of key definition in szKey
- JET_GRBIT grbit; // index options
- unsigned long ulDensity; // index density
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szIndexName; // index name
+ JET_PWSTR szKey; // index key definition
+ JET_UINT32 cbKey; // size of key definition in szKey
+ JET_GRBIT grbit; // index options
+ JET_UINT32 ulDensity; // index density
union
{
- unsigned long lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
- JET_UNICODEINDEX *pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
+ JET_UINT32 lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
+ JET_UNICODEINDEX * pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
};
union
{
- unsigned long cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
+ JET_UINT32 cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
#if ( JET_VERSION >= 0x0502 )
- JET_TUPLELIMITS *ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
+ JET_TUPLELIMITS * ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
#endif // ! JET_VERSION >= 0x0502
};
- JET_CONDITIONALCOLUMN_W *rgconditionalcolumn; // pointer to conditional column structure
- unsigned long cConditionalColumn; // number of conditional columns
- JET_ERR err; // returned error code
+ JET_CONDITIONALCOLUMN_W * rgconditionalcolumn; // pointer to conditional column structure
+ JET_UINT32 cConditionalColumn; // number of conditional columns
+ JET_ERR err; // returned error code
} JET_INDEXCREATEOLD_W;
#ifdef JET_UNICODE
@@ -1334,63 +1353,63 @@ typedef struct tagJET_INDEXCREATEOLD_W
typedef struct tagJET_INDEXCREATE_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szIndexName; // index name
- char *szKey; // index key definition
- unsigned long cbKey; // size of key definition in szKey
- JET_GRBIT grbit; // index options
- unsigned long ulDensity; // index density
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szIndexName; // index name
+ JET_PSTR szKey; // index key definition
+ JET_UINT32 cbKey; // size of key definition in szKey
+ JET_GRBIT grbit; // index options
+ JET_UINT32 ulDensity; // index density
union
{
- unsigned long lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
- JET_UNICODEINDEX *pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
+ JET_UINT32 lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
+ JET_UNICODEINDEX * pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
};
union
{
- unsigned long cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
+ JET_UINT32 cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
#if ( JET_VERSION >= 0x0502 )
- JET_TUPLELIMITS *ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
+ JET_TUPLELIMITS * ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
#endif // ! JET_VERSION >= 0x0502
};
- JET_CONDITIONALCOLUMN_A *rgconditionalcolumn; // pointer to conditional column structure
- unsigned long cConditionalColumn; // number of conditional columns
- JET_ERR err; // returned error code
+ JET_CONDITIONALCOLUMN_A * rgconditionalcolumn; // pointer to conditional column structure
+ JET_UINT32 cConditionalColumn; // number of conditional columns
+ JET_ERR err; // returned error code
#if ( JET_VERSION >= 0x0600 )
- unsigned long cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
+ JET_UINT32 cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
#endif // JET_VERSION >= 0x0600
} JET_INDEXCREATE_A;
typedef struct tagJET_INDEXCREATE_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szIndexName; // index name
- WCHAR *szKey; // index key definition
- unsigned long cbKey; // size of key definition in szKey
- JET_GRBIT grbit; // index options
- unsigned long ulDensity; // index density
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szIndexName; // index name
+ JET_PWSTR szKey; // index key definition
+ JET_UINT32 cbKey; // size of key definition in szKey
+ JET_GRBIT grbit; // index options
+ JET_UINT32 ulDensity; // index density
union
{
- unsigned long lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
- JET_UNICODEINDEX *pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
+ JET_UINT32 lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
+ JET_UNICODEINDEX * pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
};
union
{
- unsigned long cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
+ JET_UINT32 cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
#if ( JET_VERSION >= 0x0502 )
- JET_TUPLELIMITS *ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
+ JET_TUPLELIMITS * ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
#endif // ! JET_VERSION >= 0x0502
};
- JET_CONDITIONALCOLUMN_W *rgconditionalcolumn; // pointer to conditional column structure
- unsigned long cConditionalColumn; // number of conditional columns
- JET_ERR err; // returned error code
+ JET_CONDITIONALCOLUMN_W * rgconditionalcolumn; // pointer to conditional column structure
+ JET_UINT32 cConditionalColumn; // number of conditional columns
+ JET_ERR err; // returned error code
#if ( JET_VERSION >= 0x0600 )
- unsigned long cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
+ JET_UINT32 cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
#endif // JET_VERSION >= 0x0600
} JET_INDEXCREATE_W;
@@ -1404,58 +1423,58 @@ typedef struct tagJET_INDEXCREATE_W
typedef struct tagJET_INDEXCREATE2_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szIndexName; // index name
- char *szKey; // index key definition
- unsigned long cbKey; // size of key definition in szKey
- JET_GRBIT grbit; // index options
- unsigned long ulDensity; // index density
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szIndexName; // index name
+ JET_PSTR szKey; // index key definition
+ JET_UINT32 cbKey; // size of key definition in szKey
+ JET_GRBIT grbit; // index options
+ JET_UINT32 ulDensity; // index density
union
{
- unsigned long lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
- JET_UNICODEINDEX *pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
+ JET_UINT32 lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
+ JET_UNICODEINDEX * pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
};
union
{
- unsigned long cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
- JET_TUPLELIMITS *ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
+ JET_UINT32 cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
+ JET_TUPLELIMITS * ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
};
- JET_CONDITIONALCOLUMN_A *rgconditionalcolumn; // pointer to conditional column structure
- unsigned long cConditionalColumn; // number of conditional columns
- JET_ERR err; // returned error code
- unsigned long cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
- JET_SPACEHINTS * pSpacehints; // space allocation, maintenance, and usage hints
+ JET_CONDITIONALCOLUMN_A * rgconditionalcolumn; // pointer to conditional column structure
+ JET_UINT32 cConditionalColumn; // number of conditional columns
+ JET_ERR err; // returned error code
+ JET_UINT32 cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
+ JET_SPACEHINTS * pSpacehints; // space allocation, maintenance, and usage hints
} JET_INDEXCREATE2_A;
typedef struct tagJET_INDEXCREATE2_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szIndexName; // index name
- WCHAR *szKey; // index key definition
- unsigned long cbKey; // size of key definition in szKey
- JET_GRBIT grbit; // index options
- unsigned long ulDensity; // index density
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szIndexName; // index name
+ JET_PWSTR szKey; // index key definition
+ JET_UINT32 cbKey; // size of key definition in szKey
+ JET_GRBIT grbit; // index options
+ JET_UINT32 ulDensity; // index density
union
{
- unsigned long lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
- JET_UNICODEINDEX *pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
+ JET_UINT32 lcid; // lcid for the index (if JET_bitIndexUnicode NOT specified)
+ JET_UNICODEINDEX * pidxunicode; // pointer to JET_UNICODEINDEX struct (if JET_bitIndexUnicode specified)
};
union
{
- unsigned long cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
- JET_TUPLELIMITS *ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
+ JET_UINT32 cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
+ JET_TUPLELIMITS * ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
};
- JET_CONDITIONALCOLUMN_W *rgconditionalcolumn; // pointer to conditional column structure
- unsigned long cConditionalColumn; // number of conditional columns
- JET_ERR err; // returned error code
- unsigned long cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
- JET_SPACEHINTS * pSpacehints; // space allocation, maintenance, and usage hints
+ JET_CONDITIONALCOLUMN_W * rgconditionalcolumn; // pointer to conditional column structure
+ JET_UINT32 cConditionalColumn; // number of conditional columns
+ JET_ERR err; // returned error code
+ JET_UINT32 cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
+ JET_SPACEHINTS * pSpacehints; // space allocation, maintenance, and usage hints
} JET_INDEXCREATE2_W;
#ifdef JET_UNICODE
@@ -1469,48 +1488,48 @@ typedef struct tagJET_INDEXCREATE2_W
typedef struct tagJET_INDEXCREATE3_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szIndexName; // index name
- char *szKey; // index key definition
- unsigned long cbKey; // size of key definition in szKey
- JET_GRBIT grbit; // index options
- unsigned long ulDensity; // index density
- JET_UNICODEINDEX2 *pidxunicode; // pointer to JET_UNICODEINDEX2 struct (if JET_bitIndexUnicode specified)
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szIndexName; // index name
+ JET_PSTR szKey; // index key definition
+ JET_UINT32 cbKey; // size of key definition in szKey
+ JET_GRBIT grbit; // index options
+ JET_UINT32 ulDensity; // index density
+ JET_UNICODEINDEX2 * pidxunicode; // pointer to JET_UNICODEINDEX2 struct (if JET_bitIndexUnicode specified)
union
{
- unsigned long cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
- JET_TUPLELIMITS *ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
+ JET_UINT32 cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
+ JET_TUPLELIMITS * ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
};
- JET_CONDITIONALCOLUMN_A *rgconditionalcolumn; // pointer to conditional column structure
- unsigned long cConditionalColumn; // number of conditional columns
- JET_ERR err; // returned error code
- unsigned long cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
- JET_SPACEHINTS * pSpacehints; // space allocation, maintenance, and usage hints
+ JET_CONDITIONALCOLUMN_A * rgconditionalcolumn; // pointer to conditional column structure
+ JET_UINT32 cConditionalColumn; // number of conditional columns
+ JET_ERR err; // returned error code
+ JET_UINT32 cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
+ JET_SPACEHINTS * pSpacehints; // space allocation, maintenance, and usage hints
} JET_INDEXCREATE3_A;
typedef struct tagJET_INDEXCREATE3_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szIndexName; // index name
- WCHAR *szKey; // index key definition
- unsigned long cbKey; // size of key definition in szKey
- JET_GRBIT grbit; // index options
- unsigned long ulDensity; // index density
- JET_UNICODEINDEX2 *pidxunicode; // pointer to JET_UNICODEINDEX2 struct (if JET_bitIndexUnicode specified)
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szIndexName; // index name
+ JET_PWSTR szKey; // index key definition
+ JET_UINT32 cbKey; // size of key definition in szKey
+ JET_GRBIT grbit; // index options
+ JET_UINT32 ulDensity; // index density
+ JET_UNICODEINDEX2 * pidxunicode; // pointer to JET_UNICODEINDEX2 struct (if JET_bitIndexUnicode specified)
union
{
- unsigned long cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
- JET_TUPLELIMITS *ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
+ JET_UINT32 cbVarSegMac; // maximum length of variable length columns in index key (if JET_bitIndexTupleLimits not specified)
+ JET_TUPLELIMITS * ptuplelimits; // pointer to JET_TUPLELIMITS struct (if JET_bitIndexTupleLimits specified)
};
- JET_CONDITIONALCOLUMN_W *rgconditionalcolumn; // pointer to conditional column structure
- unsigned long cConditionalColumn; // number of conditional columns
- JET_ERR err; // returned error code
- unsigned long cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
- JET_SPACEHINTS * pSpacehints; // space allocation, maintenance, and usage hints
+ JET_CONDITIONALCOLUMN_W * rgconditionalcolumn; // pointer to conditional column structure
+ JET_UINT32 cConditionalColumn; // number of conditional columns
+ JET_ERR err; // returned error code
+ JET_UINT32 cbKeyMost; // size of key preserved in index, e.g. without truncation (if JET_bitIndexKeyMost specified)
+ JET_SPACEHINTS * pSpacehints; // space allocation, maintenance, and usage hints
} JET_INDEXCREATE3_W;
#ifdef JET_UNICODE
@@ -1526,34 +1545,34 @@ typedef struct tagJET_INDEXCREATE3_W
typedef struct tagJET_TABLECREATE_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szTableName; // name of table to create.
- char *szTemplateTableName; // name of table from which to inherit base DDL
- unsigned long ulPages; // initial pages to allocate for table.
- unsigned long ulDensity; // table density.
- JET_COLUMNCREATE_A *rgcolumncreate; // array of column creation info
- unsigned long cColumns; // number of columns to create
- JET_INDEXCREATE_A *rgindexcreate; // array of index creation info
- unsigned long cIndexes; // number of indexes to create
- JET_GRBIT grbit;
- JET_TABLEID tableid; // returned tableid.
- unsigned long cCreated; // count of objects created (columns+table+indexes).
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szTableName; // name of table to create.
+ JET_PSTR szTemplateTableName; // name of table from which to inherit base DDL
+ JET_UINT32 ulPages; // initial pages to allocate for table.
+ JET_UINT32 ulDensity; // table density.
+ JET_COLUMNCREATE_A * rgcolumncreate; // array of column creation info
+ JET_UINT32 cColumns; // number of columns to create
+ JET_INDEXCREATE_A * rgindexcreate; // array of index creation info
+ JET_UINT32 cIndexes; // number of indexes to create
+ JET_GRBIT grbit;
+ JET_TABLEID tableid; // returned tableid.
+ JET_UINT32 cCreated; // count of objects created (columns+table+indexes).
} JET_TABLECREATE_A;
typedef struct tagJET_TABLECREATE_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szTableName; // name of table to create.
- WCHAR *szTemplateTableName; // name of table from which to inherit base DDL
- unsigned long ulPages; // initial pages to allocate for table.
- unsigned long ulDensity; // table density.
- JET_COLUMNCREATE_W *rgcolumncreate; // array of column creation info
- unsigned long cColumns; // number of columns to create
- JET_INDEXCREATE_W *rgindexcreate; // array of index creation info
- unsigned long cIndexes; // number of indexes to create
- JET_GRBIT grbit;
- JET_TABLEID tableid; // returned tableid.
- unsigned long cCreated; // count of objects created (columns+table+indexes).
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szTableName; // name of table to create.
+ JET_PWSTR szTemplateTableName; // name of table from which to inherit base DDL
+ JET_UINT32 ulPages; // initial pages to allocate for table.
+ JET_UINT32 ulDensity; // table density.
+ JET_COLUMNCREATE_W * rgcolumncreate; // array of column creation info
+ JET_UINT32 cColumns; // number of columns to create
+ JET_INDEXCREATE_W * rgindexcreate; // array of index creation info
+ JET_UINT32 cIndexes; // number of indexes to create
+ JET_GRBIT grbit;
+ JET_TABLEID tableid; // returned tableid.
+ JET_UINT32 cCreated; // count of objects created (columns+table+indexes).
} JET_TABLECREATE_W;
#ifdef JET_UNICODE
@@ -1565,38 +1584,38 @@ typedef struct tagJET_TABLECREATE_W
#if ( JET_VERSION >= 0x0501 )
typedef struct tagJET_TABLECREATE2_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szTableName; // name of table to create.
- char *szTemplateTableName; // name of table from which to inherit base DDL
- unsigned long ulPages; // initial pages to allocate for table.
- unsigned long ulDensity; // table density.
- JET_COLUMNCREATE_A *rgcolumncreate; // array of column creation info
- unsigned long cColumns; // number of columns to create
- JET_INDEXCREATE_A *rgindexcreate; // array of index creation info
- unsigned long cIndexes; // number of indexes to create
- char *szCallback; // callback to use for this table
- JET_CBTYP cbtyp; // when the callback should be called
- JET_GRBIT grbit;
- JET_TABLEID tableid; // returned tableid.
- unsigned long cCreated; // count of objects created (columns+table+indexes+callbacks).
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szTableName; // name of table to create.
+ JET_PSTR szTemplateTableName; // name of table from which to inherit base DDL
+ JET_UINT32 ulPages; // initial pages to allocate for table.
+ JET_UINT32 ulDensity; // table density.
+ JET_COLUMNCREATE_A * rgcolumncreate; // array of column creation info
+ JET_UINT32 cColumns; // number of columns to create
+ JET_INDEXCREATE_A * rgindexcreate; // array of index creation info
+ JET_UINT32 cIndexes; // number of indexes to create
+ JET_PSTR szCallback; // callback to use for this table
+ JET_CBTYP cbtyp; // when the callback should be called
+ JET_GRBIT grbit;
+ JET_TABLEID tableid; // returned tableid.
+ JET_UINT32 cCreated; // count of objects created (columns+table+indexes+callbacks).
} JET_TABLECREATE2_A;
typedef struct tagJET_TABLECREATE2_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szTableName; // name of table to create.
- WCHAR *szTemplateTableName; // name of table from which to inherit base DDL
- unsigned long ulPages; // initial pages to allocate for table.
- unsigned long ulDensity; // table density.
- JET_COLUMNCREATE_W *rgcolumncreate; // array of column creation info
- unsigned long cColumns; // number of columns to create
- JET_INDEXCREATE_W *rgindexcreate; // array of index creation info
- unsigned long cIndexes; // number of indexes to create
- WCHAR *szCallback; // callback to use for this table
- JET_CBTYP cbtyp; // when the callback should be called
- JET_GRBIT grbit;
- JET_TABLEID tableid; // returned tableid.
- unsigned long cCreated; // count of objects created (columns+table+indexes+callbacks).
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szTableName; // name of table to create.
+ JET_PWSTR szTemplateTableName; // name of table from which to inherit base DDL
+ JET_UINT32 ulPages; // initial pages to allocate for table.
+ JET_UINT32 ulDensity; // table density.
+ JET_COLUMNCREATE_W * rgcolumncreate; // array of column creation info
+ JET_UINT32 cColumns; // number of columns to create
+ JET_INDEXCREATE_W * rgindexcreate; // array of index creation info
+ JET_UINT32 cIndexes; // number of indexes to create
+ JET_PWSTR szCallback; // callback to use for this table
+ JET_CBTYP cbtyp; // when the callback should be called
+ JET_GRBIT grbit;
+ JET_TABLEID tableid; // returned tableid.
+ JET_UINT32 cCreated; // count of objects created (columns+table+indexes+callbacks).
} JET_TABLECREATE2_W;
#ifdef JET_UNICODE
@@ -1611,45 +1630,45 @@ typedef struct tagJET_TABLECREATE2_W
#if ( JET_VERSION >= 0x0601 )
typedef struct tagJET_TABLECREATE3_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szTableName; // name of table to create.
- char *szTemplateTableName; // name of table from which to inherit base DDL
- unsigned long ulPages; // initial pages to allocate for table.
- unsigned long ulDensity; // table density.
- JET_COLUMNCREATE_A *rgcolumncreate; // array of column creation info
- unsigned long cColumns; // number of columns to create
- JET_INDEXCREATE2_A *rgindexcreate; // array of index creation info
- unsigned long cIndexes; // number of indexes to create
- char *szCallback; // callback to use for this table
- JET_CBTYP cbtyp; // when the callback should be called
- JET_GRBIT grbit;
- JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
- JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
- unsigned long cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
-
- JET_TABLEID tableid; // returned tableid.
- unsigned long cCreated; // count of objects created (columns+table+indexes+callbacks).
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szTableName; // name of table to create.
+ JET_PSTR szTemplateTableName; // name of table from which to inherit base DDL
+ JET_UINT32 ulPages; // initial pages to allocate for table.
+ JET_UINT32 ulDensity; // table density.
+ JET_COLUMNCREATE_A * rgcolumncreate; // array of column creation info
+ JET_UINT32 cColumns; // number of columns to create
+ JET_INDEXCREATE2_A * rgindexcreate; // array of index creation info
+ JET_UINT32 cIndexes; // number of indexes to create
+ JET_PSTR szCallback; // callback to use for this table
+ JET_CBTYP cbtyp; // when the callback should be called
+ JET_GRBIT grbit;
+ JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
+ JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
+ JET_UINT32 cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
+
+ JET_TABLEID tableid; // returned tableid.
+ JET_UINT32 cCreated; // count of objects created (columns+table+indexes+callbacks).
} JET_TABLECREATE3_A;
typedef struct tagJET_TABLECREATE3_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szTableName; // name of table to create.
- WCHAR *szTemplateTableName; // name of table from which to inherit base DDL
- unsigned long ulPages; // initial pages to allocate for table.
- unsigned long ulDensity; // table density.
- JET_COLUMNCREATE_W *rgcolumncreate; // array of column creation info
- unsigned long cColumns; // number of columns to create
- JET_INDEXCREATE2_W *rgindexcreate; // array of index creation info
- unsigned long cIndexes; // number of indexes to create
- WCHAR *szCallback; // callback to use for this table
- JET_CBTYP cbtyp; // when the callback should be called
- JET_GRBIT grbit;
- JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
- JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
- unsigned long cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
- JET_TABLEID tableid; // returned tableid.
- unsigned long cCreated; // count of objects created (columns+table+indexes+callbacks).
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szTableName; // name of table to create.
+ JET_PWSTR szTemplateTableName; // name of table from which to inherit base DDL
+ JET_UINT32 ulPages; // initial pages to allocate for table.
+ JET_UINT32 ulDensity; // table density.
+ JET_COLUMNCREATE_W * rgcolumncreate; // array of column creation info
+ JET_UINT32 cColumns; // number of columns to create
+ JET_INDEXCREATE2_W * rgindexcreate; // array of index creation info
+ JET_UINT32 cIndexes; // number of indexes to create
+ JET_PWSTR szCallback; // callback to use for this table
+ JET_CBTYP cbtyp; // when the callback should be called
+ JET_GRBIT grbit;
+ JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
+ JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
+ JET_UINT32 cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
+ JET_TABLEID tableid; // returned tableid.
+ JET_UINT32 cCreated; // count of objects created (columns+table+indexes+callbacks).
} JET_TABLECREATE3_W;
#ifdef JET_UNICODE
@@ -1663,46 +1682,46 @@ typedef struct tagJET_TABLECREATE3_W
#if ( JET_VERSION >= 0x0602 )
typedef struct tagJET_TABLECREATE4_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szTableName; // name of table to create.
- char *szTemplateTableName; // name of table from which to inherit base DDL
- unsigned long ulPages; // initial pages to allocate for table.
- unsigned long ulDensity; // table density.
- JET_COLUMNCREATE_A *rgcolumncreate; // array of column creation info
- unsigned long cColumns; // number of columns to create
- JET_INDEXCREATE3_A *rgindexcreate; // array of index creation info
- unsigned long cIndexes; // number of indexes to create
- char *szCallback; // callback to use for this table
- JET_CBTYP cbtyp; // when the callback should be called
- JET_GRBIT grbit;
- JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
- JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
- unsigned long cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
-
- JET_TABLEID tableid; // returned tableid.
- unsigned long cCreated; // count of objects created (columns+table+indexes+callbacks).
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szTableName; // name of table to create.
+ JET_PSTR szTemplateTableName; // name of table from which to inherit base DDL
+ JET_UINT32 ulPages; // initial pages to allocate for table.
+ JET_UINT32 ulDensity; // table density.
+ JET_COLUMNCREATE_A * rgcolumncreate; // array of column creation info
+ JET_UINT32 cColumns; // number of columns to create
+ JET_INDEXCREATE3_A * rgindexcreate; // array of index creation info
+ JET_UINT32 cIndexes; // number of indexes to create
+ JET_PSTR szCallback; // callback to use for this table
+ JET_CBTYP cbtyp; // when the callback should be called
+ JET_GRBIT grbit;
+ JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
+ JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
+ JET_UINT32 cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
+
+ JET_TABLEID tableid; // returned tableid.
+ JET_UINT32 cCreated; // count of objects created (columns+table+indexes+callbacks).
} JET_TABLECREATE4_A;
typedef struct tagJET_TABLECREATE4_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szTableName; // name of table to create.
- WCHAR *szTemplateTableName; // name of table from which to inherit base DDL
- unsigned long ulPages; // initial pages to allocate for table.
- unsigned long ulDensity; // table density.
- JET_COLUMNCREATE_W *rgcolumncreate; // array of column creation info
- unsigned long cColumns; // number of columns to create
- JET_INDEXCREATE3_W *rgindexcreate; // array of index creation info
- unsigned long cIndexes; // number of indexes to create
- WCHAR *szCallback; // callback to use for this table
- JET_CBTYP cbtyp; // when the callback should be called
- JET_GRBIT grbit;
- JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
- JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
- unsigned long cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
-
- JET_TABLEID tableid; // returned tableid.
- unsigned long cCreated; // count of objects created (columns+table+indexes+callbacks).
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szTableName; // name of table to create.
+ JET_PWSTR szTemplateTableName; // name of table from which to inherit base DDL
+ JET_UINT32 ulPages; // initial pages to allocate for table.
+ JET_UINT32 ulDensity; // table density.
+ JET_COLUMNCREATE_W * rgcolumncreate; // array of column creation info
+ JET_UINT32 cColumns; // number of columns to create
+ JET_INDEXCREATE3_W * rgindexcreate; // array of index creation info
+ JET_UINT32 cIndexes; // number of indexes to create
+ JET_PWSTR szCallback; // callback to use for this table
+ JET_CBTYP cbtyp; // when the callback should be called
+ JET_GRBIT grbit;
+ JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
+ JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
+ JET_UINT32 cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
+
+ JET_TABLEID tableid; // returned tableid.
+ JET_UINT32 cCreated; // count of objects created (columns+table+indexes+callbacks).
} JET_TABLECREATE4_W;
#ifdef JET_UNICODE
@@ -1717,48 +1736,48 @@ typedef struct tagJET_TABLECREATE4_W
#if ( JET_VERSION >= 0x0A01 )
typedef struct tagJET_TABLECREATE5_A
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- char *szTableName; // name of table to create.
- char *szTemplateTableName; // name of table from which to inherit base DDL
- unsigned long ulPages; // initial pages to allocate for table.
- unsigned long ulDensity; // table density.
- JET_COLUMNCREATE_A *rgcolumncreate; // array of column creation info
- unsigned long cColumns; // number of columns to create
- JET_INDEXCREATE3_A *rgindexcreate; // array of index creation info
- unsigned long cIndexes; // number of indexes to create
- char *szCallback; // callback to use for this table
- JET_CBTYP cbtyp; // when the callback should be called
- JET_GRBIT grbit;
- JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
- JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
- unsigned long cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
- unsigned long cbLVChunkMax; // Maximum chunk size to use for Separated LVs
-
- JET_TABLEID tableid; // returned tableid.
- unsigned long cCreated; // count of objects created (columns+table+indexes+callbacks).
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PSTR szTableName; // name of table to create.
+ JET_PSTR szTemplateTableName; // name of table from which to inherit base DDL
+ JET_UINT32 ulPages; // initial pages to allocate for table.
+ JET_UINT32 ulDensity; // table density.
+ JET_COLUMNCREATE_A * rgcolumncreate; // array of column creation info
+ JET_UINT32 cColumns; // number of columns to create
+ JET_INDEXCREATE3_A * rgindexcreate; // array of index creation info
+ JET_UINT32 cIndexes; // number of indexes to create
+ JET_PSTR szCallback; // callback to use for this table
+ JET_CBTYP cbtyp; // when the callback should be called
+ JET_GRBIT grbit;
+ JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
+ JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
+ JET_UINT32 cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
+ JET_UINT32 cbLVChunkMax; // Maximum chunk size to use for Separated LVs
+
+ JET_TABLEID tableid; // returned tableid.
+ JET_UINT32 cCreated; // count of objects created (columns+table+indexes+callbacks).
} JET_TABLECREATE5_A;
typedef struct tagJET_TABLECREATE5_W
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- WCHAR *szTableName; // name of table to create.
- WCHAR *szTemplateTableName; // name of table from which to inherit base DDL
- unsigned long ulPages; // initial pages to allocate for table.
- unsigned long ulDensity; // table density.
- JET_COLUMNCREATE_W *rgcolumncreate; // array of column creation info
- unsigned long cColumns; // number of columns to create
- JET_INDEXCREATE3_W *rgindexcreate; // array of index creation info
- unsigned long cIndexes; // number of indexes to create
- WCHAR *szCallback; // callback to use for this table
- JET_CBTYP cbtyp; // when the callback should be called
- JET_GRBIT grbit;
- JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
- JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
- unsigned long cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
- unsigned long cbLVChunkMax; // Maximum chunk size to use for Separated LVs
-
- JET_TABLEID tableid; // returned tableid.
- unsigned long cCreated; // count of objects created (columns+table+indexes+callbacks).
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ JET_PWSTR szTableName; // name of table to create.
+ JET_PWSTR szTemplateTableName; // name of table from which to inherit base DDL
+ JET_UINT32 ulPages; // initial pages to allocate for table.
+ JET_UINT32 ulDensity; // table density.
+ JET_COLUMNCREATE_W * rgcolumncreate; // array of column creation info
+ JET_UINT32 cColumns; // number of columns to create
+ JET_INDEXCREATE3_W * rgindexcreate; // array of index creation info
+ JET_UINT32 cIndexes; // number of indexes to create
+ JET_PWSTR szCallback; // callback to use for this table
+ JET_CBTYP cbtyp; // when the callback should be called
+ JET_GRBIT grbit;
+ JET_SPACEHINTS * pSeqSpacehints; // space allocation, maintenance, and usage hints for default sequential index
+ JET_SPACEHINTS * pLVSpacehints; // space allocation, maintenance, and usage hints for Separated LV tree.
+ JET_UINT32 cbSeparateLV; // heuristic size to separate a intrinsic LV from the primary record
+ JET_UINT32 cbLVChunkMax; // Maximum chunk size to use for Separated LVs
+
+ JET_TABLEID tableid; // returned tableid.
+ JET_UINT32 cCreated; // count of objects created (columns+table+indexes+callbacks).
} JET_TABLECREATE5_W;
#ifdef JET_UNICODE
@@ -1773,54 +1792,54 @@ typedef struct tagJET_TABLECREATE5_W
#if ( JET_VERSION >= 0x0600 )
typedef struct tagJET_OPENTEMPORARYTABLE
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- const JET_COLUMNDEF *prgcolumndef;
- unsigned long ccolumn;
- JET_UNICODEINDEX *pidxunicode;
- JET_GRBIT grbit;
- JET_COLUMNID *prgcolumnid;
- unsigned long cbKeyMost;
- unsigned long cbVarSegMac;
- JET_TABLEID tableid;
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ const JET_COLUMNDEF * prgcolumndef;
+ JET_UINT32 ccolumn;
+ JET_UNICODEINDEX * pidxunicode;
+ JET_GRBIT grbit;
+ JET_COLUMNID * prgcolumnid;
+ JET_UINT32 cbKeyMost;
+ JET_UINT32 cbVarSegMac;
+ JET_TABLEID tableid;
} JET_OPENTEMPORARYTABLE;
#endif // JET_VERSION >= 0x0600
#if ( JET_VERSION >= 0x0602 )
typedef struct tagJET_OPENTEMPORARYTABLE2
{
- unsigned long cbStruct; // size of this structure (for future expansion)
- const JET_COLUMNDEF *prgcolumndef;
- unsigned long ccolumn;
- JET_UNICODEINDEX2 *pidxunicode;
- JET_GRBIT grbit;
- JET_COLUMNID *prgcolumnid;
- unsigned long cbKeyMost;
- unsigned long cbVarSegMac;
- JET_TABLEID tableid;
+ JET_UINT32 cbStruct; // size of this structure (for future expansion)
+ const JET_COLUMNDEF * prgcolumndef;
+ JET_UINT32 ccolumn;
+ JET_UNICODEINDEX2 * pidxunicode;
+ JET_GRBIT grbit;
+ JET_COLUMNID * prgcolumnid;
+ JET_UINT32 cbKeyMost;
+ JET_UINT32 cbVarSegMac;
+ JET_TABLEID tableid;
} JET_OPENTEMPORARYTABLE2;
#endif // JET_VERSION >= 0x0602
typedef struct
{
- unsigned long cbStruct;
- unsigned long ibLongValue;
- unsigned long itagSequence;
+ JET_UINT32 cbStruct;
+ JET_UINT32 ibLongValue;
+ JET_UINT32 itagSequence;
JET_COLUMNID columnidNextTagged;
} JET_RETINFO;
typedef struct
{
- unsigned long cbStruct;
- unsigned long ibLongValue;
- unsigned long itagSequence;
+ JET_UINT32 cbStruct;
+ JET_UINT32 ibLongValue;
+ JET_UINT32 itagSequence;
} JET_SETINFO;
typedef struct
{
- unsigned long cbStruct;
- unsigned long centriesLT;
- unsigned long centriesInRange;
- unsigned long centriesTotal;
+ JET_UINT32 cbStruct;
+ JET_UINT32 centriesLT;
+ JET_UINT32 centriesInRange;
+ JET_UINT32 centriesTotal;
} JET_RECPOS;
// On input to JetGotoPosition, centriesLTDeprecated and centriesTotalDeprecated must be 0.
@@ -1828,25 +1847,25 @@ typedef struct
// hold potentially truncated versions of centriesLT and centriesTotal.
typedef struct
{
- unsigned long cbStruct;
- unsigned long centriesLTDeprecated;
- unsigned long centriesInRangeDeprecated;
- unsigned long centriesTotalDeprecated;
- unsigned long long centriesLT;
- unsigned long long centriesTotal;
+ JET_UINT32 cbStruct;
+ JET_UINT32 centriesLTDeprecated;
+ JET_UINT32 centriesInRangeDeprecated;
+ JET_UINT32 centriesTotalDeprecated;
+ JET_UINT64 centriesLT;
+ JET_UINT64 centriesTotal;
} JET_RECPOS2;
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_TABLEID tableid;
- unsigned long cRecord;
+ JET_UINT32 cRecord;
JET_COLUMNID columnidBookmark;
} JET_RECORDLIST;
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_TABLEID tableid;
JET_GRBIT grbit;
} JET_INDEXRANGE;
@@ -1872,17 +1891,17 @@ typedef struct
{
JET_COLUMNID columnid; // columnid of the column
JET_RELOP relop; // relational operator
- void * pv; // pointer to the value to use
- unsigned long cb; // size of the value to use
+ JET_PVOID pv; // pointer to the value to use
+ JET_UINT32 cb; // size of the value to use
JET_GRBIT grbit; // optional grbits
} JET_INDEX_COLUMN;
typedef struct
{
JET_INDEX_COLUMN * rgStartColumns;
- unsigned long cStartColumns;
+ JET_UINT32 cStartColumns;
JET_INDEX_COLUMN * rgEndColumns;
- unsigned long cEndColumns;
+ JET_UINT32 cEndColumns;
} JET_INDEX_RANGE;
#endif // JET_VERSION >= 0x0602
@@ -1905,15 +1924,15 @@ typedef enum
#if ( JET_VERSION >= 0x0501 )
typedef struct tagDDLADDCALLBACK_A
{
- char *szTable;
- char *szCallback;
+ JET_PSTR szTable;
+ JET_PSTR szCallback;
JET_CBTYP cbtyp;
} JET_DDLADDCALLBACK_A;
typedef struct tagDDLADDCALLBACK_W
{
- WCHAR *szTable;
- WCHAR *szCallback;
+ JET_PWSTR szTable;
+ JET_PWSTR szCallback;
JET_CBTYP cbtyp;
} JET_DDLADDCALLBACK_W;
@@ -1926,16 +1945,16 @@ typedef struct tagDDLADDCALLBACK_W
typedef struct tagDDLCHANGECOLUMN_A
{
- char *szTable;
- char *szColumn;
+ JET_PSTR szTable;
+ JET_PSTR szColumn;
JET_COLTYP coltypNew;
JET_GRBIT grbitNew;
} JET_DDLCHANGECOLUMN_A;
typedef struct tagDDLCHANGECOLUMN_W
{
- WCHAR *szTable;
- WCHAR *szColumn;
+ JET_PWSTR szTable;
+ JET_PWSTR szColumn;
JET_COLTYP coltypNew;
JET_GRBIT grbitNew;
} JET_DDLCHANGECOLUMN_W;
@@ -1950,16 +1969,16 @@ typedef struct tagDDLCHANGECOLUMN_W
typedef struct tagDDLMAXCOLUMNSIZE_A
{
- char *szTable;
- char *szColumn;
- unsigned long cbMax;
+ JET_PSTR szTable;
+ JET_PSTR szColumn;
+ JET_UINT32 cbMax;
} JET_DDLMAXCOLUMNSIZE_A;
typedef struct tagDDLMAXCOLUMNSIZE_W
{
- WCHAR *szTable;
- WCHAR *szColumn;
- unsigned long cbMax;
+ JET_PWSTR szTable;
+ JET_PWSTR szColumn;
+ JET_UINT32 cbMax;
} JET_DDLMAXCOLUMNSIZE_W;
#ifdef JET_UNICODE
@@ -1970,16 +1989,16 @@ typedef struct tagDDLMAXCOLUMNSIZE_W
typedef struct tagDDLADDCONDITIONALCOLUMNSTOALLINDEXES_A
{
- char * szTable; // name of table to convert
- JET_CONDITIONALCOLUMN_A * rgconditionalcolumn; // pointer to conditional column structure
- unsigned long cConditionalColumn; // number of conditional columns
+ JET_PSTR szTable; // name of table to convert
+ JET_CONDITIONALCOLUMN_A * rgconditionalcolumn; // pointer to conditional column structure
+ JET_UINT32 cConditionalColumn; // number of conditional columns
} JET_DDLADDCONDITIONALCOLUMNSTOALLINDEXES_A;
typedef struct tagDDLADDCONDITIONALCOLUMNSTOALLINDEXES_W
{
- WCHAR * szTable; // name of table to convert
- JET_CONDITIONALCOLUMN_W * rgconditionalcolumn; // pointer to conditional column structure
- unsigned long cConditionalColumn; // number of conditional columns
+ JET_PWSTR szTable; // name of table to convert
+ JET_CONDITIONALCOLUMN_W * rgconditionalcolumn; // pointer to conditional column structure
+ JET_UINT32 cConditionalColumn; // number of conditional columns
} JET_DDLADDCONDITIONALCOLUMNSTOALLINDEXES_W;
#ifdef JET_UNICODE
@@ -1991,20 +2010,20 @@ typedef struct tagDDLADDCONDITIONALCOLUMNSTOALLINDEXES_W
typedef struct tagDDLADDCOLUMCALLBACK_A
{
- char *szTable;
- char *szColumn;
- char *szCallback;
- void *pvCallbackData;
- unsigned long cbCallbackData;
+ JET_PSTR szTable;
+ JET_PSTR szColumn;
+ JET_PSTR szCallback;
+ JET_PVOID pvCallbackData;
+ JET_UINT32 cbCallbackData;
} JET_DDLADDCOLUMNCALLBACK_A;
typedef struct tagDDLADDCOLUMCALLBACK_W
{
- WCHAR *szTable;
- WCHAR *szColumn;
- WCHAR *szCallback;
- void *pvCallbackData;
- unsigned long cbCallbackData;
+ JET_PWSTR szTable;
+ JET_PWSTR szColumn;
+ JET_PWSTR szCallback;
+ JET_PVOID pvCallbackData;
+ JET_UINT32 cbCallbackData;
} JET_DDLADDCOLUMNCALLBACK_W;
#ifdef JET_UNICODE
@@ -2015,16 +2034,16 @@ typedef struct tagDDLADDCOLUMCALLBACK_W
typedef struct tagDDLINDEXDENSITY_A
{
- char *szTable;
- char *szIndex; // pass NULL to change density of primary index
- unsigned long ulDensity;
+ JET_PSTR szTable;
+ JET_PSTR szIndex; // pass NULL to change density of primary index
+ JET_UINT32 ulDensity;
} JET_DDLINDEXDENSITY_A;
typedef struct tagDDLINDEXDENSITY_W
{
- WCHAR *szTable;
- WCHAR *szIndex; // pass NULL to change density of primary index
- unsigned long ulDensity;
+ JET_PWSTR szTable;
+ JET_PWSTR szIndex; // pass NULL to change density of primary index
+ JET_UINT32 ulDensity;
} JET_DDLINDEXDENSITY_W;
#ifdef JET_UNICODE
@@ -2035,14 +2054,14 @@ typedef struct tagDDLINDEXDENSITY_W
typedef struct tagDDLCALLBACKDLL_A
{
- char *szOldDLL;
- char *szNewDLL;
+ JET_PSTR szOldDLL;
+ JET_PSTR szNewDLL;
} JET_DDLCALLBACKDLL_A;
typedef struct tagDDLCALLBACKDLL_W
{
- WCHAR *szOldDLL;
- WCHAR *szNewDLL;
+ JET_PWSTR szOldDLL;
+ JET_PWSTR szNewDLL;
} JET_DDLCALLBACKDLL_W;
#ifdef JET_UNICODE
@@ -2056,11 +2075,11 @@ typedef struct tagDDLCALLBACKDLL_W
typedef struct
{
- void *pvReserved1; // internally use
- void *pvReserved2;
- unsigned long cbActual; // the actual number of bytes read through this IO
+ JET_PVOID pvReserved1; // internally use
+ JET_PVOID pvReserved2;
+ JET_UINT32 cbActual; // the actual number of bytes read through this IO
JET_HANDLE hSig; // a manual reset signal to wait for the IO to complete.
- JET_ERR err; // Err code for this assync IO.
+ JET_ERR err; // Err code for this assync IO.
} JET_OLP;
// begin_PubEsent
@@ -2070,29 +2089,29 @@ typedef struct
typedef struct
{
- char bSeconds; // 0 - 59
- char bMinutes; // 0 - 59
- char bHours; // 0 - 23
- char bDay; // 1 - 31
- char bMonth; // 1 - 12
- char bYear; // current year - 1900
+ JET_INT8 bSeconds; // 0 - 59
+ JET_INT8 bMinutes; // 0 - 59
+ JET_INT8 bHours; // 0 - 23
+ JET_INT8 bDay; // 1 - 31
+ JET_INT8 bMonth; // 1 - 12
+ JET_INT8 bYear; // current year - 1900
union
{
- char bFiller1;
+ JET_BYTE bFiller1;
struct
{
- unsigned char fTimeIsUTC:1;
- unsigned char bMillisecondsLow:7;
+ JET_BYTE fTimeIsUTC:1;
+ JET_BYTE bMillisecondsLow:7;
};
};
union
{
- char bFiller2;
+ JET_BYTE bFiller2;
struct
{
- unsigned char fReserved:1;
- unsigned char bMillisecondsHigh:3;
- unsigned char fUnused:4;
+ JET_BYTE fReserved:1;
+ JET_BYTE bMillisecondsHigh:3;
+ JET_BYTE fUnused:4;
};
};
} JET_LOGTIME;
@@ -2103,29 +2122,29 @@ typedef struct
// compatibility reasons
typedef struct
{
- char bSeconds; // 0 - 59
- char bMinutes; // 0 - 59
- char bHours; // 0 - 23
- char bDay; // 1 - 31
- char bMonth; // 1 - 12
- char bYear; // current year - 1900
+ JET_INT8 bSeconds; // 0 - 59
+ JET_INT8 bMinutes; // 0 - 59
+ JET_INT8 bHours; // 0 - 23
+ JET_INT8 bDay; // 1 - 31
+ JET_INT8 bMonth; // 1 - 12
+ JET_INT8 bYear; // current year - 1900
union
{
- char bFiller1;
+ JET_BYTE bFiller1;
struct
{
- unsigned char fTimeIsUTC:1;
- unsigned char bMillisecondsLow:7;
+ JET_BYTE fTimeIsUTC:1;
+ JET_BYTE bMillisecondsLow:7;
};
};
union
{
- char bFiller2;
+ JET_BYTE bFiller2;
struct
{
- unsigned char fOSSnapshot:1;
- unsigned char bMillisecondsHigh:3;
- unsigned char fReserved:4;
+ JET_BYTE fOSSnapshot:1;
+ JET_BYTE bMillisecondsHigh:3;
+ JET_BYTE fReserved:4;
};
};
} JET_BKLOGTIME;
@@ -2133,24 +2152,24 @@ typedef struct
typedef struct
{
- unsigned short ib; // must be the last so that lgpos can
- unsigned short isec; // index of disksec starting logsec
- long lGeneration; // generation of logsec
+ JET_UINT16 ib; // must be the last so that lgpos can
+ JET_UINT16 isec; // index of disksec starting logsec
+ JET_INT32 lGeneration; // generation of logsec
} JET_LGPOS; // be casted to TIME.
typedef struct
{
- unsigned long ulRandom; // a random number
+ JET_UINT32 ulRandom; // a random number
JET_LOGTIME logtimeCreate; // time db created, in logtime format
- char szComputerName[ JET_MAX_COMPUTERNAME_LENGTH + 1 ]; // where db is created
+ JET_CHAR szComputerName[ JET_MAX_COMPUTERNAME_LENGTH + 1 ]; // where db is created
} JET_SIGNATURE;
// end_PubEsent
#if ( JET_VERSION >= 0x0600 )
typedef struct
{
- unsigned long genMin;
- unsigned long genMax;
+ JET_UINT32 genMin;
+ JET_UINT32 genMax;
JET_LOGTIME logtimeGenMaxCreate;
} JET_CHECKPOINTINFO;
#endif // JET_VERSION >= 0x0600
@@ -2166,19 +2185,19 @@ typedef struct
JET_BKLOGTIME bklogtimeMark;
#endif // JET_VERSION >= 0x0600
};
- unsigned long genLow;
- unsigned long genHigh;
+ JET_UINT32 genLow;
+ JET_UINT32 genHigh;
} JET_BKINFO;
#include
typedef struct
{
- unsigned long ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
- unsigned long ulUpdate; // used to track incremental database format "update (major)" version from the
+ JET_UINT32 ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
+ JET_UINT32 ulUpdate; // used to track incremental database format "update (major)" version from the
// last attach/create that is a backward-compatible major update.
JET_SIGNATURE signDb; // (28 bytes) signature of the db (incl. creation time).
- unsigned long dbstate; // consistent/inconsistent state
+ JET_UINT32 dbstate; // consistent/inconsistent state
JET_LGPOS lgposConsistent; // null if in inconsistent state
JET_LOGTIME logtimeConsistent; // null if in inconsistent state
@@ -2197,29 +2216,29 @@ typedef struct
// Reset when bkinfoFullPrev is set
JET_BKINFO bkinfoFullCur; // current backup. Succeed if a
// corresponding pat file generated.
- unsigned long fShadowingDisabled;
- unsigned long fUpgradeDb;
+ JET_UINT32 fShadowingDisabled;
+ JET_UINT32 fUpgradeDb;
// NT version information. This is needed to decide if an index need
// be recreated due to sort table changes.
- unsigned long dwMajorVersion; /* OS version info */
- unsigned long dwMinorVersion;
- unsigned long dwBuildNumber;
- long lSPNumber;
+ JET_UINT32 dwMajorVersion; // OS version info
+ JET_UINT32 dwMinorVersion;
+ JET_UINT32 dwBuildNumber;
+ JET_INT32 lSPNumber;
- unsigned long cbPageSize; // database page size (0 = 4k pages)
+ JET_UINT32 cbPageSize; // database page size (0 = 4k pages)
} JET_DBINFOMISC;
#if ( JET_VERSION >= 0x0600 )
typedef struct
{
- unsigned long ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
- unsigned long ulUpdate; // used to track incremental database format "update (major)" version from the
+ JET_UINT32 ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
+ JET_UINT32 ulUpdate; // used to track incremental database format "update (major)" version from the
// last attach/create that is a backward-compatible major update.
JET_SIGNATURE signDb; // (28 bytes) signature of the db (incl. creation time).
- unsigned long dbstate; // consistent/inconsistent state
+ JET_UINT32 dbstate; // consistent/inconsistent state
JET_LGPOS lgposConsistent; // null if in inconsistent state
JET_LOGTIME logtimeConsistent; // null if in inconsistent state
@@ -2238,39 +2257,39 @@ typedef struct
// Reset when bkinfoFullPrev is set
JET_BKINFO bkinfoFullCur; // current backup. Succeed if a
// corresponding pat file generated.
- unsigned long fShadowingDisabled;
- unsigned long fUpgradeDb;
+ JET_UINT32 fShadowingDisabled;
+ JET_UINT32 fUpgradeDb;
// NT version information. This is needed to decide if an index need
// be recreated due to sort table changes.
- unsigned long dwMajorVersion; /* OS version info */
- unsigned long dwMinorVersion;
- unsigned long dwBuildNumber;
- long lSPNumber;
+ JET_UINT32 dwMajorVersion; // OS version info
+ JET_UINT32 dwMinorVersion;
+ JET_UINT32 dwBuildNumber;
+ JET_INT32 lSPNumber;
- unsigned long cbPageSize; // database page size (0 = 4k pages)
+ JET_UINT32 cbPageSize; // database page size (0 = 4k pages)
// new fields added on top of the above JET_DBINFOMISC
- unsigned long genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
- unsigned long genMaxRequired; // the maximum log generation required for replaying the logs.
+ JET_UINT32 genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
+ JET_UINT32 genMaxRequired; // the maximum log generation required for replaying the logs.
JET_LOGTIME logtimeGenMaxCreate; // creation time of the genMax log file
- unsigned long ulRepairCount; // number of times repair has been called on this database
+ JET_UINT32 ulRepairCount; // number of times repair has been called on this database
JET_LOGTIME logtimeRepair; // the date of the last time that repair was run
- unsigned long ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
+ JET_UINT32 ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
- unsigned long ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
+ JET_UINT32 ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
JET_LOGTIME logtimeECCFixSuccess; // the date of the last time that a one bit error was fixed and resulted in a good page
- unsigned long ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
+ JET_UINT32 ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
- unsigned long ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
+ JET_UINT32 ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
JET_LOGTIME logtimeECCFixFail; // the date of the last time that a one bit error was fixed and resulted in a bad page
- unsigned long ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
+ JET_UINT32 ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
- unsigned long ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
+ JET_UINT32 ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
JET_LOGTIME logtimeBadChecksum; // the date of the last time that a non-correctable ECC/checksum error was found
- unsigned long ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
+ JET_UINT32 ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
} JET_DBINFOMISC2;
#endif // JET_VERSION >= 0x0600
@@ -2278,11 +2297,11 @@ typedef struct
#if ( JET_VERSION >= 0x0601 )
typedef struct
{
- unsigned long ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
- unsigned long ulUpdate; // used to track incremental database format "update (major)" version from the
+ JET_UINT32 ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
+ JET_UINT32 ulUpdate; // used to track incremental database format "update (major)" version from the
// last attach/create that is a backward-compatible major update.
JET_SIGNATURE signDb; // (28 bytes) signature of the db (incl. creation time).
- unsigned long dbstate; // consistent/inconsistent state
+ JET_UINT32 dbstate; // consistent/inconsistent state
JET_LGPOS lgposConsistent; // null if in inconsistent state
JET_LOGTIME logtimeConsistent; // null if in inconsistent state
@@ -2301,52 +2320,52 @@ typedef struct
// Reset when bkinfoFullPrev is set
JET_BKINFO bkinfoFullCur; // current backup. Succeed if a
// corresponding pat file generated.
- unsigned long fShadowingDisabled;
- unsigned long fUpgradeDb;
+ JET_UINT32 fShadowingDisabled;
+ JET_UINT32 fUpgradeDb;
// NT version information. This is needed to decide if an index need
// be recreated due to sort table changes.
- unsigned long dwMajorVersion; /* OS version info */
- unsigned long dwMinorVersion;
- unsigned long dwBuildNumber;
- long lSPNumber;
+ JET_UINT32 dwMajorVersion; // OS version info
+ JET_UINT32 dwMinorVersion;
+ JET_UINT32 dwBuildNumber;
+ JET_INT32 lSPNumber;
- unsigned long cbPageSize; // database page size (0 = 4k pages)
+ JET_UINT32 cbPageSize; // database page size (0 = 4k pages)
// new fields added on top of the above JET_DBINFOMISC
- unsigned long genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
- unsigned long genMaxRequired; // the maximum log generation required for replaying the logs.
+ JET_UINT32 genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
+ JET_UINT32 genMaxRequired; // the maximum log generation required for replaying the logs.
JET_LOGTIME logtimeGenMaxCreate; // creation time of the genMax log file
- unsigned long ulRepairCount; // number of times repair has been called on this database
+ JET_UINT32 ulRepairCount; // number of times repair has been called on this database
JET_LOGTIME logtimeRepair; // the date of the last time that repair was run
- unsigned long ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
+ JET_UINT32 ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
- unsigned long ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
+ JET_UINT32 ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
JET_LOGTIME logtimeECCFixSuccess; // the date of the last time that a one bit error was fixed and resulted in a good page
- unsigned long ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
+ JET_UINT32 ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
- unsigned long ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
+ JET_UINT32 ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
JET_LOGTIME logtimeECCFixFail; // the date of the last time that a one bit error was fixed and resulted in a bad page
- unsigned long ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
+ JET_UINT32 ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
- unsigned long ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
+ JET_UINT32 ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
JET_LOGTIME logtimeBadChecksum; // the date of the last time that a non-correctable ECC/checksum error was found
- unsigned long ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
+ JET_UINT32 ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
// new fields added on top of the above JET_DBINFOMISC2
- unsigned long genCommitted; // the maximum log generation committed to the database. Typically the current log generation
+ JET_UINT32 genCommitted; // the maximum log generation committed to the database. Typically the current log generation
} JET_DBINFOMISC3;
typedef struct
{
- unsigned long ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
- unsigned long ulUpdate; // used to track incremental database format "update (major)" version from the
+ JET_UINT32 ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
+ JET_UINT32 ulUpdate; // used to track incremental database format "update (major)" version from the
// last attach/create that is a backward-compatible major update.
JET_SIGNATURE signDb; // (28 bytes) signature of the db (incl. creation time).
- unsigned long dbstate; // consistent/inconsistent state
+ JET_UINT32 dbstate; // consistent/inconsistent state
JET_LGPOS lgposConsistent; // null if in inconsistent state
JET_LOGTIME logtimeConsistent; // null if in inconsistent state
@@ -2365,42 +2384,42 @@ typedef struct
// Reset when bkinfoFullPrev is set
JET_BKINFO bkinfoFullCur; // current backup. Succeed if a
// corresponding pat file generated.
- unsigned long fShadowingDisabled;
- unsigned long fUpgradeDb;
+ JET_UINT32 fShadowingDisabled;
+ JET_UINT32 fUpgradeDb;
// NT version information. This is needed to decide if an index need
// be recreated due to sort table changes.
- unsigned long dwMajorVersion; /* OS version info */
- unsigned long dwMinorVersion;
- unsigned long dwBuildNumber;
- long lSPNumber;
+ JET_UINT32 dwMajorVersion; // OS version info
+ JET_UINT32 dwMinorVersion;
+ JET_UINT32 dwBuildNumber;
+ JET_INT32 lSPNumber;
- unsigned long cbPageSize; // database page size (0 = 4k pages)
+ JET_UINT32 cbPageSize; // database page size (0 = 4k pages)
// new fields added on top of the above JET_DBINFOMISC
- unsigned long genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
- unsigned long genMaxRequired; // the maximum log generation required for replaying the logs.
+ JET_UINT32 genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
+ JET_UINT32 genMaxRequired; // the maximum log generation required for replaying the logs.
JET_LOGTIME logtimeGenMaxCreate; // creation time of the genMax log file
- unsigned long ulRepairCount; // number of times repair has been called on this database
+ JET_UINT32 ulRepairCount; // number of times repair has been called on this database
JET_LOGTIME logtimeRepair; // the date of the last time that repair was run
- unsigned long ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
+ JET_UINT32 ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
- unsigned long ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
+ JET_UINT32 ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
JET_LOGTIME logtimeECCFixSuccess; // the date of the last time that a one bit error was fixed and resulted in a good page
- unsigned long ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
+ JET_UINT32 ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
- unsigned long ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
+ JET_UINT32 ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
JET_LOGTIME logtimeECCFixFail; // the date of the last time that a one bit error was fixed and resulted in a bad page
- unsigned long ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
+ JET_UINT32 ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
- unsigned long ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
+ JET_UINT32 ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
JET_LOGTIME logtimeBadChecksum; // the date of the last time that a non-correctable ECC/checksum error was found
- unsigned long ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
+ JET_UINT32 ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
// new fields added on top of the above JET_DBINFOMISC2
- unsigned long genCommitted; // the maximum log generation committed to the database. Typically the current log generation
+ JET_UINT32 genCommitted; // the maximum log generation committed to the database. Typically the current log generation
// new fields added on top of the above JET_DBINFOMISC3
JET_BKINFO bkinfoCopyPrev; // Last successful Copy backup
@@ -2412,11 +2431,11 @@ typedef struct
#if ( JET_VERSION >= 0x0601 )
typedef struct
{
- unsigned long ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
- unsigned long ulUpdate; // used to track incremental database format "update (major)" version from the
+ JET_UINT32 ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
+ JET_UINT32 ulUpdate; // used to track incremental database format "update (major)" version from the
// last attach/create that is a backward-compatible major update.
JET_SIGNATURE signDb; // (28 bytes) signature of the db (incl. creation time).
- unsigned long dbstate; // consistent/inconsistent state
+ JET_UINT32 dbstate; // consistent/inconsistent state
JET_LGPOS lgposConsistent; // null if in inconsistent state
JET_LOGTIME logtimeConsistent; // null if in inconsistent state
@@ -2435,64 +2454,64 @@ typedef struct
// Reset when bkinfoFullPrev is set
JET_BKINFO bkinfoFullCur; // current backup. Succeed if a
// corresponding pat file generated.
- unsigned long fShadowingDisabled;
- unsigned long fUpgradeDb;
+ JET_UINT32 fShadowingDisabled;
+ JET_UINT32 fUpgradeDb;
// NT version information. This is needed to decide if an index need
// be recreated due to sort table changes.
- unsigned long dwMajorVersion; /* OS version info */
- unsigned long dwMinorVersion;
- unsigned long dwBuildNumber;
- long lSPNumber;
+ JET_UINT32 dwMajorVersion; // OS version info
+ JET_UINT32 dwMinorVersion;
+ JET_UINT32 dwBuildNumber;
+ JET_INT32 lSPNumber;
- unsigned long cbPageSize; // database page size (0 = 4k pages)
+ JET_UINT32 cbPageSize; // database page size (0 = 4k pages)
// new fields added on top of the above JET_DBINFOMISC
- unsigned long genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
- unsigned long genMaxRequired; // the maximum log generation required for replaying the logs.
+ JET_UINT32 genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
+ JET_UINT32 genMaxRequired; // the maximum log generation required for replaying the logs.
JET_LOGTIME logtimeGenMaxCreate; // creation time of the genMax log file
- unsigned long ulRepairCount; // number of times repair has been called on this database
+ JET_UINT32 ulRepairCount; // number of times repair has been called on this database
JET_LOGTIME logtimeRepair; // the date of the last time that repair was run
- unsigned long ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
+ JET_UINT32 ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
- unsigned long ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
+ JET_UINT32 ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
JET_LOGTIME logtimeECCFixSuccess; // the date of the last time that a one bit error was fixed and resulted in a good page
- unsigned long ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
+ JET_UINT32 ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
- unsigned long ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
+ JET_UINT32 ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
JET_LOGTIME logtimeECCFixFail; // the date of the last time that a one bit error was fixed and resulted in a bad page
- unsigned long ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
+ JET_UINT32 ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
- unsigned long ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
+ JET_UINT32 ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
JET_LOGTIME logtimeBadChecksum; // the date of the last time that a non-correctable ECC/checksum error was found
- unsigned long ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
+ JET_UINT32 ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
// new fields added on top of the above JET_DBINFOMISC2
- unsigned long genCommitted; // the maximum log generation committed to the database. Typically the current log generation
+ JET_UINT32 genCommitted; // the maximum log generation committed to the database. Typically the current log generation
// new fields added on top of the above JET_DBINFOMISC3
JET_BKINFO bkinfoCopyPrev; // Last successful Copy backup
JET_BKINFO bkinfoDiffPrev; // Last successful Differential backup, reset when bkinfoFullPrev is set
// new fields added on top of the above JET_DBINFOMISC4
- unsigned long ulIncrementalReseedCount; // number of times incremental reseed has been initiated on this database
+ JET_UINT32 ulIncrementalReseedCount; // number of times incremental reseed has been initiated on this database
JET_LOGTIME logtimeIncrementalReseed; // the date of the last time that incremental reseed was initiated on this database
- unsigned long ulIncrementalReseedCountOld; // number of times incremental reseed was initiated on this database before the last defrag
+ JET_UINT32 ulIncrementalReseedCountOld; // number of times incremental reseed was initiated on this database before the last defrag
- unsigned long ulPagePatchCount; // number of pages patched in the database as a part of incremental reseed
+ JET_UINT32 ulPagePatchCount; // number of pages patched in the database as a part of incremental reseed
JET_LOGTIME logtimePagePatch; // the date of the last time that a page was patched as a part of incremental reseed
- unsigned long ulPagePatchCountOld; // number of pages patched in the database as a part of incremental reseed before the last defrag
+ JET_UINT32 ulPagePatchCountOld; // number of pages patched in the database as a part of incremental reseed before the last defrag
} JET_DBINFOMISC5;
typedef struct
{
- unsigned long ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
- unsigned long ulUpdate; // used to track incremental database format "update (major)" version from the
+ JET_UINT32 ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
+ JET_UINT32 ulUpdate; // used to track incremental database format "update (major)" version from the
// last attach/create that is a backward-compatible major update.
JET_SIGNATURE signDb; // (28 bytes) signature of the db (incl. creation time).
- unsigned long dbstate; // consistent/inconsistent state
+ JET_UINT32 dbstate; // consistent/inconsistent state
JET_LGPOS lgposConsistent; // null if in inconsistent state
JET_LOGTIME logtimeConsistent; // null if in inconsistent state
@@ -2511,71 +2530,71 @@ typedef struct
// Reset when bkinfoFullPrev is set
JET_BKINFO bkinfoFullCur; // current backup. Succeed if a
// corresponding pat file generated.
- unsigned long fShadowingDisabled;
- unsigned long fUpgradeDb;
+ JET_UINT32 fShadowingDisabled;
+ JET_UINT32 fUpgradeDb;
// NT version information. This is needed to decide if an index need
// be recreated due to sort table changes.
- unsigned long dwMajorVersion; /* OS version info */
- unsigned long dwMinorVersion;
- unsigned long dwBuildNumber;
- long lSPNumber;
+ JET_UINT32 dwMajorVersion; // OS version info
+ JET_UINT32 dwMinorVersion;
+ JET_UINT32 dwBuildNumber;
+ JET_INT32 lSPNumber;
- unsigned long cbPageSize; // database page size (0 = 4k pages)
+ JET_UINT32 cbPageSize; // database page size (0 = 4k pages)
// new fields added on top of the above JET_DBINFOMISC
- unsigned long genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
- unsigned long genMaxRequired; // the maximum log generation required for replaying the logs.
+ JET_UINT32 genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
+ JET_UINT32 genMaxRequired; // the maximum log generation required for replaying the logs.
JET_LOGTIME logtimeGenMaxCreate; // creation time of the genMax log file
- unsigned long ulRepairCount; // number of times repair has been called on this database
+ JET_UINT32 ulRepairCount; // number of times repair has been called on this database
JET_LOGTIME logtimeRepair; // the date of the last time that repair was run
- unsigned long ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
+ JET_UINT32 ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
- unsigned long ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
+ JET_UINT32 ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
JET_LOGTIME logtimeECCFixSuccess; // the date of the last time that a one bit error was fixed and resulted in a good page
- unsigned long ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
+ JET_UINT32 ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
- unsigned long ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
+ JET_UINT32 ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
JET_LOGTIME logtimeECCFixFail; // the date of the last time that a one bit error was fixed and resulted in a bad page
- unsigned long ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
+ JET_UINT32 ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
- unsigned long ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
+ JET_UINT32 ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
JET_LOGTIME logtimeBadChecksum; // the date of the last time that a non-correctable ECC/checksum error was found
- unsigned long ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
+ JET_UINT32 ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
// new fields added on top of the above JET_DBINFOMISC2
- unsigned long genCommitted; // the maximum log generation committed to the database. Typically the current log generation
+ JET_UINT32 genCommitted; // the maximum log generation committed to the database. Typically the current log generation
// new fields added on top of the above JET_DBINFOMISC3
JET_BKINFO bkinfoCopyPrev; // Last successful Copy backup
JET_BKINFO bkinfoDiffPrev; // Last successful Differential backup, reset when bkinfoFullPrev is set
// new fields added on top of the above JET_DBINFOMISC4
- unsigned long ulIncrementalReseedCount; // number of times incremental reseed has been initiated on this database
+ JET_UINT32 ulIncrementalReseedCount; // number of times incremental reseed has been initiated on this database
JET_LOGTIME logtimeIncrementalReseed; // the date of the last time that incremental reseed was initiated on this database
- unsigned long ulIncrementalReseedCountOld; // number of times incremental reseed was initiated on this database before the last defrag
+ JET_UINT32 ulIncrementalReseedCountOld; // number of times incremental reseed was initiated on this database before the last defrag
- unsigned long ulPagePatchCount; // number of pages patched in the database as a part of incremental reseed
+ JET_UINT32 ulPagePatchCount; // number of pages patched in the database as a part of incremental reseed
JET_LOGTIME logtimePagePatch; // the date of the last time that a page was patched as a part of incremental reseed
- unsigned long ulPagePatchCountOld; // number of pages patched in the database as a part of incremental reseed before the last defrag
+ JET_UINT32 ulPagePatchCountOld; // number of pages patched in the database as a part of incremental reseed before the last defrag
// new fields added on top of the above JET_DBINFOMISC5
JET_LOGTIME logtimeChecksumPrev; // last checksum pass finish time (UTC - 1900y)
JET_LOGTIME logtimeChecksumStart; // current checksum pass start time (UTC - 1900y)
- unsigned long cpgDatabaseChecked; // # of page checked for current pass
+ JET_UINT32 cpgDatabaseChecked; // # of page checked for current pass
} JET_DBINFOMISC6;
#endif // JET_VERSION >= 0x0601
#if ( JET_VERSION >= 0x0A00 )
typedef struct
{
- unsigned long ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
- unsigned long ulUpdate; // used to track incremental database format "update (major)" version from the
+ JET_UINT32 ulVersion; // the major (incompatible) version of DAE from the last engine attach/create.
+ JET_UINT32 ulUpdate; // used to track incremental database format "update (major)" version from the
// last attach/create that is a backward-compatible major update.
JET_SIGNATURE signDb; // (28 bytes) signature of the db (incl. creation time).
- unsigned long dbstate; // consistent/inconsistent state
+ JET_UINT32 dbstate; // consistent/inconsistent state
JET_LGPOS lgposConsistent; // null if in inconsistent state
JET_LOGTIME logtimeConsistent; // null if in inconsistent state
@@ -2594,60 +2613,60 @@ typedef struct
// Reset when bkinfoFullPrev is set
JET_BKINFO bkinfoFullCur; // current backup. Succeed if a
// corresponding pat file generated.
- unsigned long fShadowingDisabled;
- unsigned long fUpgradeDb;
+ JET_UINT32 fShadowingDisabled;
+ JET_UINT32 fUpgradeDb;
// NT version information. This is needed to decide if an index need
// be recreated due to sort table changes.
- unsigned long dwMajorVersion; /* OS version info */
- unsigned long dwMinorVersion;
- unsigned long dwBuildNumber;
- long lSPNumber;
+ JET_UINT32 dwMajorVersion; // OS version info
+ JET_UINT32 dwMinorVersion;
+ JET_UINT32 dwBuildNumber;
+ JET_INT32 lSPNumber;
- unsigned long cbPageSize; // database page size (0 = 4k pages)
+ JET_UINT32 cbPageSize; // database page size (0 = 4k pages)
// new fields added on top of the above JET_DBINFOMISC
- unsigned long genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
- unsigned long genMaxRequired; // the maximum log generation required for replaying the logs.
+ JET_UINT32 genMinRequired; // the minimum log generation required for replaying the logs. Typically the checkpoint generation
+ JET_UINT32 genMaxRequired; // the maximum log generation required for replaying the logs.
JET_LOGTIME logtimeGenMaxCreate; // creation time of the genMax log file
- unsigned long ulRepairCount; // number of times repair has been called on this database
+ JET_UINT32 ulRepairCount; // number of times repair has been called on this database
JET_LOGTIME logtimeRepair; // the date of the last time that repair was run
- unsigned long ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
+ JET_UINT32 ulRepairCountOld; // number of times ErrREPAIRAttachForRepair has been called on this database before the last defrag
- unsigned long ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
+ JET_UINT32 ulECCFixSuccess; // number of times a one bit error was fixed and resulted in a good page
JET_LOGTIME logtimeECCFixSuccess; // the date of the last time that a one bit error was fixed and resulted in a good page
- unsigned long ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
+ JET_UINT32 ulECCFixSuccessOld; // number of times a one bit error was fixed and resulted in a good page before last repair
- unsigned long ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
+ JET_UINT32 ulECCFixFail; // number of times a one bit error was fixed and resulted in a bad page
JET_LOGTIME logtimeECCFixFail; // the date of the last time that a one bit error was fixed and resulted in a bad page
- unsigned long ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
+ JET_UINT32 ulECCFixFailOld; // number of times a one bit error was fixed and resulted in a bad page before last repair
- unsigned long ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
+ JET_UINT32 ulBadChecksum; // number of times a non-correctable ECC/checksum error was found
JET_LOGTIME logtimeBadChecksum; // the date of the last time that a non-correctable ECC/checksum error was found
- unsigned long ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
+ JET_UINT32 ulBadChecksumOld; // number of times a non-correctable ECC/checksum error was found before last repair
// new fields added on top of the above JET_DBINFOMISC2
- unsigned long genCommitted; // the maximum log generation committed to the database. Typically the current log generation
+ JET_UINT32 genCommitted; // the maximum log generation committed to the database. Typically the current log generation
// new fields added on top of the above JET_DBINFOMISC3
JET_BKINFO bkinfoCopyPrev; // Last successful Copy backup
JET_BKINFO bkinfoDiffPrev; // Last successful Differential backup, reset when bkinfoFullPrev is set
// new fields added on top of the above JET_DBINFOMISC4
- unsigned long ulIncrementalReseedCount; // number of times incremental reseed has been initiated on this database
+ JET_UINT32 ulIncrementalReseedCount; // number of times incremental reseed has been initiated on this database
JET_LOGTIME logtimeIncrementalReseed; // the date of the last time that incremental reseed was initiated on this database
- unsigned long ulIncrementalReseedCountOld; // number of times incremental reseed was initiated on this database before the last defrag
+ JET_UINT32 ulIncrementalReseedCountOld; // number of times incremental reseed was initiated on this database before the last defrag
- unsigned long ulPagePatchCount; // number of pages patched in the database as a part of incremental reseed
+ JET_UINT32 ulPagePatchCount; // number of pages patched in the database as a part of incremental reseed
JET_LOGTIME logtimePagePatch; // the date of the last time that a page was patched as a part of incremental reseed
- unsigned long ulPagePatchCountOld; // number of pages patched in the database as a part of incremental reseed before the last defrag
+ JET_UINT32 ulPagePatchCountOld; // number of pages patched in the database as a part of incremental reseed before the last defrag
// new fields added on top of the above JET_DBINFOMISC5
- JET_LOGTIME logtimeChecksumPrev; // last checksum pass finish time (UTC - 1900y)
- JET_LOGTIME logtimeChecksumStart; // current checksum pass start time (UTC - 1900y)
- unsigned long cpgDatabaseChecked; // # of page checked for current pass
+ JET_LOGTIME logtimeChecksumPrev; // last checksum pass finish time (UTC - 1900y)
+ JET_LOGTIME logtimeChecksumStart; // current checksum pass start time (UTC - 1900y)
+ JET_UINT32 cpgDatabaseChecked; // # of page checked for current pass
// new fields added on top of the above JET_DBINFOMISC6
JET_LOGTIME logtimeLastReAttach; // Last attach time.
@@ -2657,43 +2676,43 @@ typedef struct
typedef struct
{
- unsigned long ulGeneration;
+ JET_UINT32 ulGeneration;
JET_SIGNATURE signLog;
JET_LOGTIME logtimeCreate;
JET_LOGTIME logtimePreviousGeneration;
- unsigned long ulFlags;
+ JET_UINT32 ulFlags;
- unsigned long ulVersionMajor;
- unsigned long ulVersionMinor;
- unsigned long ulVersionUpdate;
+ JET_UINT32 ulVersionMajor;
+ JET_UINT32 ulVersionMinor;
+ JET_UINT32 ulVersionUpdate;
- unsigned long cbSectorSize;
- unsigned long cbHeader;
- unsigned long cbFile;
- unsigned long cbDatabasePageSize;
+ JET_UINT32 cbSectorSize;
+ JET_UINT32 cbHeader;
+ JET_UINT32 cbFile;
+ JET_UINT32 cbDatabasePageSize;
} JET_LOGINFOMISC;
#if ( JET_VERSION >= 0x0601 )
typedef struct
{
- unsigned long ulGeneration;
+ JET_UINT32 ulGeneration;
JET_SIGNATURE signLog;
JET_LOGTIME logtimeCreate;
JET_LOGTIME logtimePreviousGeneration;
- unsigned long ulFlags;
+ JET_UINT32 ulFlags;
- unsigned long ulVersionMajor;
- unsigned long ulVersionMinor;
- unsigned long ulVersionUpdate;
+ JET_UINT32 ulVersionMajor;
+ JET_UINT32 ulVersionMinor;
+ JET_UINT32 ulVersionUpdate;
- unsigned long cbSectorSize;
- unsigned long cbHeader;
- unsigned long cbFile;
- unsigned long cbDatabasePageSize;
+ JET_UINT32 cbSectorSize;
+ JET_UINT32 cbHeader;
+ JET_UINT32 cbFile;
+ JET_UINT32 cbDatabasePageSize;
JET_LGPOS lgposCheckpoint;
} JET_LOGINFOMISC2;
@@ -2703,28 +2722,28 @@ typedef struct
#if ( JET_VERSION >= 0x0A01 )
typedef struct
{
- unsigned long ulGeneration;
+ JET_UINT32 ulGeneration;
JET_SIGNATURE signLog;
JET_LOGTIME logtimeCreate;
JET_LOGTIME logtimePreviousGeneration;
- unsigned long ulFlags;
+ JET_UINT32 ulFlags;
- unsigned long ulVersionMajor;
- unsigned long ulVersionUpdateMajor;
- unsigned long ulVersionUpdateMinor;
+ JET_UINT32 ulVersionMajor;
+ JET_UINT32 ulVersionUpdateMajor;
+ JET_UINT32 ulVersionUpdateMinor;
- unsigned long cbSectorSize;
- unsigned long cbHeader;
- unsigned long cbFile;
- unsigned long cbDatabasePageSize;
+ JET_UINT32 cbSectorSize;
+ JET_UINT32 cbHeader;
+ JET_UINT32 cbFile;
+ JET_UINT32 cbDatabasePageSize;
JET_LGPOS lgposCheckpoint;
- unsigned long ulVersionMinorDeprecated; // deprecated
+ JET_UINT32 ulVersionMinorDeprecated; // deprecated
- unsigned __int64 checksumPrevLogAllSegments;
+ JET_UINT64 checksumPrevLogAllSegments;
} JET_LOGINFOMISC3;
@@ -2789,32 +2808,32 @@ typedef struct
typedef struct
{
- unsigned long cbStruct; /* size of this structure */
- JET_ERR errDefault; /* given no desired special treatment, the client should return this */
- JET_INSTANCE instance; /* the instance for which recovery is run */
+ JET_UINT32 cbStruct; // size of this structure
+ JET_ERR errDefault; // given no desired special treatment, the client should return this
+ JET_INSTANCE instance; // the instance for which recovery is run
- JET_SNT sntUnion; /* indicates the type for the union */
+ JET_SNT sntUnion; // indicates the type for the union
union {
// JET_sntOpenLog
struct
{
- unsigned long cbStruct; /* size of this structure */
- unsigned long lGenNext; /* next log to be replayed */
- unsigned char fCurrentLog:1; /* 0 if log with full / archive name */
- unsigned char eReason; /* the open disposition or reason - JET_OpenLog* */
- unsigned char rgbReserved[6]; /* will be 0 */
- WCHAR * wszLogFile; /* full path of the log file we will open */
- unsigned long cdbinfomisc; /* number of database headers */
- JET_DBINFOMISC7 * rgdbinfomisc; /* array of database headers for attached databases */
+ JET_UINT32 cbStruct; // size of this structure
+ JET_UINT32 lGenNext; // next log to be replayed
+ JET_BYTE fCurrentLog:1; // 0 if log with full / archive name
+ JET_BYTE eReason; // the open disposition or reason - JET_OpenLog*
+ JET_BYTE rgbReserved[6]; // will be 0
+ JET_PWSTR wszLogFile; // full path of the log file we will open
+ JET_UINT32 cdbinfomisc; // number of database headers
+ JET_DBINFOMISC7 * rgdbinfomisc; // array of database headers for attached databases
} OpenLog;
// JET_sntOpenCheckpoint
struct
{
- unsigned long cbStruct; /* size of this structure */
- WCHAR * wszCheckpoint; /* full path of the checkpoint file we will open */
+ JET_UINT32 cbStruct; // size of this structure
+ JET_PWSTR wszCheckpoint; // full path of the checkpoint file we will open
} OpenCheckpoint;
// JET_sntOpenDatabase not yet implemented.
@@ -2822,59 +2841,59 @@ typedef struct
// JET_sntMissingLog
struct
{
- unsigned long cbStruct; /* size of this structure */
- unsigned long lGenMissing; /* next log to be replayed */
- unsigned char fCurrentLog:1; /* 0 if log with full / archive name */
- unsigned char eNextAction; /* if success is returned, what action will we take */
- unsigned char rgbReserved[6]; /* will be 0 */
- WCHAR * wszLogFile; /* full path of the log file we will open */
- unsigned long cdbinfomisc; /* number of database headers */
- JET_DBINFOMISC7 * rgdbinfomisc; /* array of database headers for attached databases */
+ JET_UINT32 cbStruct; // size of this structure
+ JET_UINT32 lGenMissing; // next log to be replayed
+ JET_BYTE fCurrentLog:1; // 0 if log with full / archive name
+ JET_BYTE eNextAction; // if success is returned, what action will we take
+ JET_BYTE rgbReserved[6]; // will be 0
+ JET_PWSTR wszLogFile; // full path of the log file we will open
+ JET_UINT32 cdbinfomisc; // number of database headers
+ JET_DBINFOMISC7 * rgdbinfomisc; // array of database headers for attached databases
} MissingLog;
// JET_sntBeginUndo
struct
{
- unsigned long cbStruct; /* size of this structure */
- unsigned long cdbinfomisc; /* number of database headers */
- JET_DBINFOMISC7 * rgdbinfomisc; /* array of database headers for attached databases */
+ JET_UINT32 cbStruct; // size of this structure
+ JET_UINT32 cdbinfomisc; // number of database headers
+ JET_DBINFOMISC7 * rgdbinfomisc; // array of database headers for attached databases
} BeginUndo;
// JET_sntNotificationEvent
struct
{
- unsigned long cbStruct; /* size of this structure */
- unsigned long EventID; /* ID of the event we would publish */
+ JET_UINT32 cbStruct; // size of this structure
+ JET_UINT32 EventID; // ID of the event we would publish
} NotificationEvent;
// JET_sntSignalErrorCondition
struct
{
- unsigned long cbStruct; /* size of this structure */
+ JET_UINT32 cbStruct; // size of this structure
// no extra info beyond errDefault above
} SignalErrorCondition;
// JET_sntAttachedDb
struct
{
- unsigned long cbStruct; /* size of this structure */
- const WCHAR * wszDbPath; /* full path of the database file */
+ JET_UINT32 cbStruct; // size of this structure
+ JET_PCWSTR wszDbPath; // full path of the database file
} AttachedDb;
// JET_sntDetachingDb
struct
{
- unsigned long cbStruct; /* size of this structure */
- const WCHAR * wszDbPath; /* full path of the database file */
+ JET_UINT32 cbStruct; // size of this structure
+ JET_PCWSTR wszDbPath; // full path of the database file
} DetachingDb;
// JET_sntCommitCtx
struct
{
- unsigned long cbStruct; /* size of this structure */
- const void * pbCommitCtx; /* commit context */
- unsigned long cbCommitCtx; /* size of commit context */
- unsigned long fCallbackType; /* type of callback */
+ JET_UINT32 cbStruct; // size of this structure
+ JET_PCVOID pbCommitCtx; // commit context
+ JET_UINT32 cbCommitCtx; // size of commit context
+ JET_UINT32 fCallbackType; // type of callback
} CommitCtx;
};
} JET_RECOVERYCONTROL;
@@ -2885,12 +2904,12 @@ typedef struct
#endif // JET_VERSION >= 0x0A00
#if ( JET_VERSION >= 0x0600 )
-typedef struct /* Status Notification Message */
+typedef struct // Status Notification Message
{
- unsigned long cbStruct; /* Size of this structure */
- JET_SNC snc; /* Status Notification Code */
- unsigned long ul; /* Numeric identifier */
- char sz[256]; /* Identifier */
+ JET_UINT32 cbStruct; // Size of this structure
+ JET_SNC snc; // Status Notification Code
+ JET_UINT32 ul; // Numeric identifier
+ JET_CHAR sz[256]; // Identifier
} JET_SNMSG;
#endif // JET_VERSION >= 0x0600
@@ -2899,32 +2918,32 @@ typedef struct /* Status Notification Message */
typedef struct // Status Notification Page Patch Request
{
- unsigned long cbStruct; // Size of this structure
- unsigned long pageNumber; // Page being patched
- const WCHAR * szLogFile; // Full path of the current logfile
+ JET_UINT32 cbStruct; // Size of this structure
+ JET_UINT32 pageNumber; // Page being patched
+ JET_PCWSTR szLogFile; // Full path of the current logfile
JET_INSTANCE instance; // Instance that is running recovery
JET_DBINFOMISC7 dbinfomisc; // Database header for the database being patched
- const void * pvToken; // Patch token
- unsigned long cbToken; // Size of the patch token
- const void * pvData; // Patch data (the database page)
- unsigned long cbData; // Size of the patch data
+ JET_PCVOID pvToken; // Patch token
+ JET_UINT32 cbToken; // Size of the patch token
+ JET_PCVOID pvData; // Patch data (the database page)
+ JET_UINT32 cbData; // Size of the patch data
JET_DBID dbid; // JET_DBID of database being patched
} JET_SNPATCHREQUEST;
typedef struct // Status Notification Corrupted Page
{
- unsigned long cbStruct; // Size of this structure
- const WCHAR * wszDatabase; // File name of the database corrupted
+ JET_UINT32 cbStruct; // Size of this structure
+ JET_PCWSTR wszDatabase; // File name of the database corrupted
JET_DBID dbid; // JET_DBID of database corrupted
JET_DBINFOMISC7 dbinfomisc; // Database header for corrupted database
- unsigned long pageNumber; // That is corrupted
+ JET_UINT32 pageNumber; // That is corrupted
} JET_SNCORRUPTEDPAGE;
#endif // JET_VERSION >= 0x0A01
typedef struct
{
- unsigned long cpageOwned; // number of owned pages in the streaming file
- unsigned long cpageAvail; // number of available pages in the streaming file (subset of cpageOwned)
+ JET_UINT32 cpageOwned; // number of owned pages in the streaming file
+ JET_UINT32 cpageAvail; // number of available pages in the streaming file (subset of cpageOwned)
} JET_STREAMINGFILESPACEINFO;
// begin_PubEsent
@@ -2934,14 +2953,14 @@ typedef struct
//
struct JET_THREADSTATS
{
- unsigned long cbStruct; // size of this struct
- unsigned long cPageReferenced; // pages referenced
- unsigned long cPageRead; // pages read from disk
- unsigned long cPagePreread; // pages preread from disk
- unsigned long cPageDirtied; // clean pages modified
- unsigned long cPageRedirtied; // dirty pages modified
- unsigned long cLogRecord; // log records generated
- unsigned long cbLogRecord; // log record bytes generated
+ JET_UINT32 cbStruct; // size of this struct
+ JET_UINT32 cPageReferenced; // pages referenced
+ JET_UINT32 cPageRead; // pages read from disk
+ JET_UINT32 cPagePreread; // pages preread from disk
+ JET_UINT32 cPageDirtied; // clean pages modified
+ JET_UINT32 cPageRedirtied; // dirty pages modified
+ JET_UINT32 cLogRecord; // log records generated
+ JET_UINT32 cbLogRecord; // log record bytes generated
};
#endif // JET_VERSION >= 0x0600
@@ -2950,16 +2969,16 @@ struct JET_THREADSTATS
//
struct JET_THREADSTATS2
{
- unsigned long cbStruct; // size of this struct
- unsigned long cPageReferenced; // pages referenced
- unsigned long cPageRead; // pages read from disk
- unsigned long cPagePreread; // pages preread from disk
- unsigned long cPageDirtied; // clean pages modified
- unsigned long cPageRedirtied; // dirty pages modified
- unsigned long cLogRecord; // log records generated
- unsigned long cbLogRecord; // log record bytes generated
- unsigned __int64 cusecPageCacheMiss; // page cache miss latency in microseconds
- unsigned long cPageCacheMiss; // page cache misses
+ JET_UINT32 cbStruct; // size of this struct
+ JET_UINT32 cPageReferenced; // pages referenced
+ JET_UINT32 cPageRead; // pages read from disk
+ JET_UINT32 cPagePreread; // pages preread from disk
+ JET_UINT32 cPageDirtied; // clean pages modified
+ JET_UINT32 cPageRedirtied; // dirty pages modified
+ JET_UINT32 cLogRecord; // log records generated
+ JET_UINT32 cbLogRecord; // log record bytes generated
+ JET_UINT64 cusecPageCacheMiss; // page cache miss latency in microseconds
+ JET_UINT32 cPageCacheMiss; // page cache misses
};
#endif // JET_VERSION >= 0x0A00
@@ -2968,19 +2987,19 @@ struct JET_THREADSTATS2
//
struct JET_THREADSTATS3
{
- unsigned long cbStruct; // size of this struct
- unsigned long cPageReferenced; // pages referenced
- unsigned long cPageRead; // pages read from disk
- unsigned long cPagePreread; // pages preread from disk
- unsigned long cPageDirtied; // clean pages modified
- unsigned long cPageRedirtied; // dirty pages modified
- unsigned long cLogRecord; // log records generated
- unsigned long cbLogRecord; // log record bytes generated
- unsigned __int64 cusecPageCacheMiss; // page cache miss latency in microseconds
- unsigned long cPageCacheMiss; // page cache misses
- unsigned long cSeparatedLongValueRead; // separated LV reads
- unsigned __int64 cusecLongValuePageCacheMiss; // page cache miss latency in microseconds while reading separated LV data
- unsigned long cLongValuePageCacheMiss; // page cache misses while reading separated LV data
+ JET_UINT32 cbStruct; // size of this struct
+ JET_UINT32 cPageReferenced; // pages referenced
+ JET_UINT32 cPageRead; // pages read from disk
+ JET_UINT32 cPagePreread; // pages preread from disk
+ JET_UINT32 cPageDirtied; // clean pages modified
+ JET_UINT32 cPageRedirtied; // dirty pages modified
+ JET_UINT32 cLogRecord; // log records generated
+ JET_UINT32 cbLogRecord; // log record bytes generated
+ JET_UINT64 cusecPageCacheMiss; // page cache miss latency in microseconds
+ JET_UINT32 cPageCacheMiss; // page cache misses
+ JET_UINT32 cSeparatedLongValueRead; // separated LV reads
+ JET_UINT64 cusecLongValuePageCacheMiss; // page cache miss latency in microseconds while reading separated LV data
+ JET_UINT32 cLongValuePageCacheMiss; // page cache misses while reading separated LV data
};
#endif // JET_VERSION >= 0x0A01
// end_PubEsent
@@ -2990,34 +3009,34 @@ struct JET_THREADSTATS3
//
struct JET_THREADSTATS4
{
- unsigned long cbStruct; // size of this struct
- unsigned long cPageReferenced; // pages referenced
- unsigned long cPageRead; // pages read from disk
- unsigned long cPagePreread; // pages preread from disk
- unsigned long cPageDirtied; // clean pages modified
- unsigned long cPageRedirtied; // dirty pages modified
- unsigned long cLogRecord; // log records generated
- unsigned long cbLogRecord; // log record bytes generated
- unsigned __int64 cusecPageCacheMiss; // page cache miss latency in microseconds
- unsigned long cPageCacheMiss; // page cache misses
- unsigned long cSeparatedLongValueRead; // separated LV reads
- unsigned __int64 cusecLongValuePageCacheMiss; // page cache miss latency in microseconds while reading separated LV data
- unsigned long cLongValuePageCacheMiss; // page cache misses while reading separated LV data
- unsigned long cSeparatedLongValueCreated; // separated LV creations
- unsigned long cPageUniqueCacheHits; // number of unique pages for which requests could be fulfilled by the buffer cache
- unsigned long cPageUniqueCacheRequests; // number of unique pages for which requests were made to the buffer cache
- unsigned long cDatabaseReads; // number of database reads from disk
- unsigned long cSumDatabaseReadQueueDepthImpact; // sum of the impact on disk queue depth made by each database read from disk
- unsigned long cSumDatabaseReadQueueDepth; // sum of the actual disk queue depths experienced by each database read from disk
- unsigned __int64 cusecWait; // elapsed thread wait time in microseconds
- unsigned long cWait; // number of thread waits
- unsigned long cNodesFlagDeleted; // number of nodes marked for delete
- unsigned long cbNodesFlagDeleted; // size of nodes marked for delete
- unsigned long cPageTableAllocated; // number of pages allocated by a table from the database
- unsigned long cPageTableReleased; // number of pages released by a table to the database
- unsigned long cPageUpdateAllocated; // number of pages allocated as a side effect of an update
- unsigned long cPageUpdateReleased; // number of pages released as a side effect of an update
- unsigned long cPageUniqueModified; // number of unique pages modified
+ JET_UINT32 cbStruct; // size of this struct
+ JET_UINT32 cPageReferenced; // pages referenced
+ JET_UINT32 cPageRead; // pages read from disk
+ JET_UINT32 cPagePreread; // pages preread from disk
+ JET_UINT32 cPageDirtied; // clean pages modified
+ JET_UINT32 cPageRedirtied; // dirty pages modified
+ JET_UINT32 cLogRecord; // log records generated
+ JET_UINT32 cbLogRecord; // log record bytes generated
+ JET_UINT64 cusecPageCacheMiss; // page cache miss latency in microseconds
+ JET_UINT32 cPageCacheMiss; // page cache misses
+ JET_UINT32 cSeparatedLongValueRead; // separated LV reads
+ JET_UINT64 cusecLongValuePageCacheMiss; // page cache miss latency in microseconds while reading separated LV data
+ JET_UINT32 cLongValuePageCacheMiss; // page cache misses while reading separated LV data
+ JET_UINT32 cSeparatedLongValueCreated; // separated LV creations
+ JET_UINT32 cPageUniqueCacheHits; // number of unique pages for which requests could be fulfilled by the buffer cache
+ JET_UINT32 cPageUniqueCacheRequests; // number of unique pages for which requests were made to the buffer cache
+ JET_UINT32 cDatabaseReads; // number of database reads from disk
+ JET_UINT32 cSumDatabaseReadQueueDepthImpact; // sum of the impact on disk queue depth made by each database read from disk
+ JET_UINT32 cSumDatabaseReadQueueDepth; // sum of the actual disk queue depths experienced by each database read from disk
+ JET_UINT64 cusecWait; // elapsed thread wait time in microseconds
+ JET_UINT32 cWait; // number of thread waits
+ JET_UINT32 cNodesFlagDeleted; // number of nodes marked for delete
+ JET_UINT32 cbNodesFlagDeleted; // size of nodes marked for delete
+ JET_UINT32 cPageTableAllocated; // number of pages allocated by a table from the database
+ JET_UINT32 cPageTableReleased; // number of pages released by a table to the database
+ JET_UINT32 cPageUpdateAllocated; // number of pages allocated as a side effect of an update
+ JET_UINT32 cPageUpdateReleased; // number of pages released as a side effect of an update
+ JET_UINT32 cPageUniqueModified; // number of unique pages modified
};
#endif // JET_VERSION >= 0x0A01
@@ -3100,10 +3119,10 @@ typedef enum
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_RSTMAP_A * rgrstmap;
- long crstmap;
+ JET_INT32 crstmap;
JET_LGPOS lgposStop;
JET_LOGTIME logtimeStop;
@@ -3113,10 +3132,10 @@ typedef struct
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_RSTMAP_W * rgrstmap;
- long crstmap;
+ JET_INT32 crstmap;
JET_LGPOS lgposStop;
JET_LOGTIME logtimeStop;
@@ -3138,30 +3157,30 @@ typedef struct
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_RSTMAP2_A * rgrstmap;
- long crstmap;
+ JET_INT32 crstmap;
JET_LGPOS lgposStop;
JET_LOGTIME logtimeStop;
JET_PFNINITCALLBACK pfnCallback;
- void * pvCallbackContext;
+ JET_PVOID pvCallbackContext;
} JET_RSTINFO2_A;
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_RSTMAP2_W * rgrstmap;
- long crstmap;
+ JET_INT32 crstmap;
JET_LGPOS lgposStop;
JET_LOGTIME logtimeStop;
JET_PFNINITCALLBACK pfnCallback;
- void * pvCallbackContext;
+ JET_PVOID pvCallbackContext;
} JET_RSTINFO2_W;
#ifdef JET_UNICODE
@@ -3219,61 +3238,61 @@ typedef enum
//
typedef struct _BTREE_STATS_BASIC_CATALOG
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_BTREETYPE eType;
- WCHAR rgName[64];
- unsigned long objidFDP;
- unsigned long pgnoFDP;
- JET_SPACEHINTS * pSpaceHints;
+ JET_WCHAR rgName[64];
+ JET_UINT32 objidFDP;
+ JET_UINT32 pgnoFDP;
+ JET_SPACEHINTS * pSpaceHints;
} BTREE_STATS_BASIC_CATALOG;
typedef struct _BTREE_SPACE_EXTENT_INFO
{
- unsigned long iPool;
- unsigned long pgnoLast;
- unsigned long cpgExtent;
- unsigned long pgnoSpaceNode;
+ JET_UINT32 iPool;
+ JET_UINT32 pgnoLast;
+ JET_UINT32 cpgExtent;
+ JET_UINT32 pgnoSpaceNode;
} BTREE_SPACE_EXTENT_INFO;
// Retrieved with JET_bitSpaceInfoSpaceTrees
//
typedef struct _BTREE_STATS_SPACE_TREES
{
- unsigned long cbStruct;
- unsigned long cpgPrimary;
- unsigned long cpgLastAlloc;
- unsigned long fMultiExtent;
- unsigned long pgnoOE;
- unsigned long pgnoAE;
- unsigned long cpgOwned;
- unsigned long cpgOwnedCache;
- unsigned long cpgAvailable;
- unsigned long cpgAvailableCache;
- unsigned long cpgSpaceTreeAvailable;
- unsigned long cpgReserved;
- unsigned long cpgShelved;
- int fAutoIncPresents;
- unsigned __int64 qwAutoInc;
- unsigned long cOwnedExtents;
- _Field_size_opt_(cOwnedExtents) BTREE_SPACE_EXTENT_INFO * prgOwnedExtents;
- unsigned long cAvailExtents;
- _Field_size_opt_(cAvailExtents) BTREE_SPACE_EXTENT_INFO * prgAvailExtents;
+ JET_UINT32 cbStruct;
+ JET_UINT32 cpgPrimary;
+ JET_UINT32 cpgLastAlloc;
+ JET_UINT32 fMultiExtent;
+ JET_UINT32 pgnoOE;
+ JET_UINT32 pgnoAE;
+ JET_UINT32 cpgOwned;
+ JET_UINT32 cpgOwnedCache;
+ JET_UINT32 cpgAvailable;
+ JET_UINT32 cpgAvailableCache;
+ JET_UINT32 cpgSpaceTreeAvailable;
+ JET_UINT32 cpgReserved;
+ JET_UINT32 cpgShelved;
+ JET_INT32 fAutoIncPresents;
+ JET_UINT64 qwAutoInc;
+ JET_UINT32 cOwnedExtents;
+ _Field_size_opt_(cOwnedExtents) BTREE_SPACE_EXTENT_INFO * prgOwnedExtents;
+ JET_UINT32 cAvailExtents;
+ _Field_size_opt_(cAvailExtents) BTREE_SPACE_EXTENT_INFO * prgAvailExtents;
} BTREE_STATS_SPACE_TREES;
// Retrieved with JET_bitSpaceInfoFullWalk for data page.
//
typedef struct
{
- unsigned long cbStruct;
- JET_HISTO * phistoFreeBytes; // per page
- JET_HISTO * phistoNodeCounts; // per page (not including TAG 0)
- JET_HISTO * phistoKeySizes; // per node
- JET_HISTO * phistoDataSizes; // per node
- JET_HISTO * phistoKeyCompression; // per compressed node
- JET_HISTO * phistoResvTagSizes; // per reserved tag
- JET_HISTO * phistoUnreclaimedBytes; // per deleted node
+ JET_UINT32 cbStruct;
+ JET_HISTO * phistoFreeBytes; // per page
+ JET_HISTO * phistoNodeCounts; // per page (not including TAG 0)
+ JET_HISTO * phistoKeySizes; // per node
+ JET_HISTO * phistoDataSizes; // per node
+ JET_HISTO * phistoKeyCompression; // per compressed node
+ JET_HISTO * phistoResvTagSizes; // per reserved tag
+ JET_HISTO * phistoUnreclaimedBytes; // per deleted node
#if ( JET_VERSION >= 0x0602 )
- __int64 cVersionedNodes; // node accumulation
+ JET_INT64 cVersionedNodes; // node accumulation
#endif
} BTREE_STATS_PAGE_SPACE;
@@ -3298,13 +3317,13 @@ typedef struct
// OE:3-pg,many fFalse? 2 1 2 3 0
typedef struct _BTREE_STATS_PARENT_OF_LEAF
{
- unsigned long cbStruct;
- unsigned long fEmpty;
- unsigned long cpgInternal;
- unsigned long cpgData;
- unsigned long cDepth;
+ JET_UINT32 cbStruct;
+ JET_UINT32 fEmpty;
+ JET_UINT32 cpgInternal;
+ JET_UINT32 cpgData;
+ JET_UINT32 cDepth;
JET_HISTO * phistoIOContiguousRuns;
- unsigned long cForwardScans;
+ JET_UINT32 cForwardScans;
BTREE_STATS_PAGE_SPACE * pInternalPageStats;
} BTREE_STATS_PARENT_OF_LEAF;
@@ -3312,13 +3331,13 @@ typedef struct _BTREE_STATS_PARENT_OF_LEAF
typedef struct _BTREE_STATS_LV
{
- unsigned long cbStruct;
- __int64 cLVRefs;
- __int64 cCorruptLVs;
- __int64 cSeparatedRootChunks;
- __int64 cPartiallyDeletedLVs;
- unsigned __int64 lidMax;
- int cbLVChunkMax;
+ JET_UINT32 cbStruct;
+ JET_INT64 cLVRefs;
+ JET_INT64 cCorruptLVs;
+ JET_INT64 cSeparatedRootChunks;
+ JET_INT64 cPartiallyDeletedLVs;
+ JET_UINT64 lidMax;
+ JET_INT32 cbLVChunkMax;
JET_HISTO * phistoLVSize;
JET_HISTO * phistoLVComp;
JET_HISTO * phistoLVRatio;
@@ -3335,8 +3354,8 @@ typedef struct _BTREE_STATS
//
// Version and specified data.
//
- unsigned long cbStruct;
- unsigned long grbitData;
+ JET_UINT32 cbStruct;
+ JET_UINT32 grbitData;
//
// ESE's B+ Trees / space are heirarchical.
//
@@ -3351,10 +3370,10 @@ typedef struct _BTREE_STATS
#if ( JET_VERSION >= 0x0602 )
BTREE_STATS_LV * pLvData;
#endif
- unsigned long fPgnoFDPRootDelete;
+ JET_UINT32 fPgnoFDPRootDelete;
} BTREE_STATS;
-typedef JET_ERR (JET_API *JET_PFNSPACEDATA)(
+typedef JET_ERR (JET_API * JET_PFNSPACEDATA)(
_In_ BTREE_STATS * pBTreeStats,
_In_ JET_API_PTR pvContext );
#endif // JET_VERSION >= 0x0601
@@ -3362,11 +3381,11 @@ typedef JET_ERR (JET_API *JET_PFNSPACEDATA)(
//typedef struct
// {
-// unsigned long cDiscont;
-// unsigned long cUnfixedMessyPage;
-// unsigned long centriesLT;
-// unsigned long centriesTotal;
-// unsigned long cpgCompactFreed;
+// JET_UINT32 cDiscont;
+// JET_UINT32 cUnfixedMessyPage;
+// JET_UINT32 centriesLT;
+// JET_UINT32 centriesTotal;
+// JET_UINT32 cpgCompactFreed;
// } JET_OLCSTAT;
// begin_PubEsent
@@ -3502,12 +3521,12 @@ typedef enum
// be populated by all error levels.
typedef struct
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_ERR errValue; // The error value for the requested info level.
JET_ERRCAT errcatMostSpecific; // The most specific category of the error.
- unsigned char rgCategoricalHierarchy[8]; // Hierarchy of error categories. Position 0 is the highest level in the hierarchy, and the rest are JET_errcatUnknown.
- unsigned long lSourceLine; // The source file line for the requested info level.
- WCHAR rgszSourceFile[64]; // The source file name for the requested info level.
+ JET_BYTE rgCategoricalHierarchy[8]; // Hierarchy of error categories. Position 0 is the highest level in the hierarchy, and the rest are JET_errcatUnknown.
+ JET_UINT32 lSourceLine; // The source file line for the requested info level.
+ JET_WCHAR rgszSourceFile[64]; // The source file name for the requested info level.
} JET_ERRINFOBASIC_W;
// grbits for JET_PFNDURABLECOMMITCALLBACK
@@ -3519,50 +3538,50 @@ typedef struct
typedef struct
{
JET_SIGNATURE signLog;
- int reserved; // for packing so int64 below is 8-byte aligned on 32-bits despite the pshpack4 above
- __int64 commitId;
+ JET_INT32 reserved; // for packing so int64 below is 8-byte aligned on 32-bits despite the pshpack4 above
+ JET_INT64 commitId;
} JET_COMMIT_ID;
// assert that commit-id is 8-byte aligned so managed interop works correctly
// C_ASSERT( offsetof( JET_COMMIT_ID, commitId ) % 8 == 0 );
// callback for JET_paramDurableCommitCallback
-typedef JET_ERR (JET_API *JET_PFNDURABLECOMMITCALLBACK)(
- _In_ JET_INSTANCE instance,
- _In_ JET_COMMIT_ID *pCommitIdSeen,
- _In_ JET_GRBIT grbit );
+typedef JET_ERR (JET_API * JET_PFNDURABLECOMMITCALLBACK)(
+ _In_ JET_INSTANCE instance,
+ _In_ JET_COMMIT_ID * pCommitIdSeen,
+ _In_ JET_GRBIT grbit );
#endif // JET_VERSION >= 0x0602
// end_PubEsent
typedef struct
{
- long lRBSGeneration; // Revert snapshot generation.
+ JET_INT32 lRBSGeneration; // Revert snapshot generation.
JET_LOGTIME logtimeCreate; // date time file creation
JET_LOGTIME logtimeCreatePrevRBS; // date time prev file creation
- unsigned long ulMajor; // major version number
- unsigned long ulMinor; // minor version number
+ JET_UINT32 ulMajor; // major version number
+ JET_UINT32 ulMinor; // minor version number
- unsigned long long cbLogicalFileSize; // Logical file size
+ JET_UINT64 cbLogicalFileSize; // Logical file size
} JET_RBSINFOMISC;
typedef struct
{
- long lGenMinRevertStart; // Min log generation across databases at start of revert.
- long lGenMaxRevertStart; // Max log generation across databases at start of revert.
+ JET_INT32 lGenMinRevertStart; // Min log generation across databases at start of revert.
+ JET_INT32 lGenMaxRevertStart; // Max log generation across databases at start of revert.
- long lGenMinRevertEnd; // Min log generation across databases at end of revert.
- long lGenMaxRevertEnd; // Max log generation across databases at end of revert.
+ JET_INT32 lGenMinRevertEnd; // Min log generation across databases at end of revert.
+ JET_INT32 lGenMaxRevertEnd; // Max log generation across databases at end of revert.
JET_LOGTIME logtimeRevertFrom; // The time we started reverting from. We will skip adding reverting to time as the caller already gets that info as part of prepare call.
- unsigned long long cSecRevert; // Total secs spent in revert process.
- unsigned long long cPagesReverted; // Total pages reverted across all the database files as part of the revert.
+ JET_UINT64 cSecRevert; // Total secs spent in revert process.
+ JET_UINT64 cPagesReverted; // Total pages reverted across all the database files as part of the revert.
- long lGenRBSMaxApplied; // Max revert snapshot generation applied during revert.
- long lGenRBSMinApplied; // Min revert snapshot generation applied during revert.
+ JET_INT32 lGenRBSMaxApplied; // Max revert snapshot generation applied during revert.
+ JET_INT32 lGenRBSMinApplied; // Min revert snapshot generation applied during revert.
} JET_RBSREVERTINFOMISC;
// begin_PubEsent
@@ -3952,7 +3971,7 @@ typedef enum
// end_PubEsent
#if ( JET_VERSION >= 0x0A01 )
-#define JET_paramFlight_SmoothIoTestPermillage 55 // The per mille of total (or one thousandths, or tenths of a percent) of IO should be made smooth. Ex(s): 995(/1000) = 99.5% smooth, 10(/1000) = 1%, etc. 0 = disabled.
+#define JET_paramFlight_HierarchicalSpaceAllocFlagsEnabled 55 // Whether we want to pass the space allocation flags along when asking for space to the parent of an object.
#define JET_paramElasticWaypointLatency 56 // Amount of extra elastic waypoint latency
#define JET_paramFlight_SynchronousLVCleanup 57 // Perform synchronous cleanup (actual delete) of LVs instead of flag delete with cleanup happening later
#define JET_paramFlight_RBSRevertIOUrgentLevel 58 // IO urgent level for reverting the databases using RBS. Used to decide how many outstanding I/Os will be allowed.
@@ -4072,8 +4091,8 @@ typedef enum
#define JET_paramFlight_ExtentPageCountCacheVerifyOnly 114 // Verify values read from the Extent Page Count Cache rather than just returning them.
#define JET_paramFlight_EnablePgnoFDPLastSetTime 115 // whether we want to enable setting PgnoPFDSetTime in the system table for a table entry.
-#define JET_paramFlight_EnableScanCheck2Flags 116 // whether we want to enable logging flags in ScanCheck2 log record.
-#define JET_paramFlight_EnableExtentFreed2 117 // whether we want to enable logging ExtentFreed2 LR after the efv upgrade.
+#define JET_paramFlight_EnableFDPDeleteFlagCheckOnExtentFreedRedo 116 // whether we want to check if FDP delete flag is set when we redo extent freed LR.
+#define JET_paramFlight_RBSRaiseCorruptionOnRBSFDPToBeDeleted 117 // Whether we want to raise corruption event/failure item when we hit RBSFDPToBeDeleted error.
#define JET_paramFlight_RBSLargeRevertableDeletePages 118 // Large revertable delete size for a table (in pages) beyond which we will track the deletes.
#define JET_paramFlight_RBSRevertableDeleteIfTooSoonTimeNull 119 // If set, we will do a revertable table delete even if NonRevertableTableDelete flag is passed provided NonRevertable delete is failing due to JET_errRBSDeleteTableTooSoon due to time not being set. Note: If JET_bitRevertableTableDeleteIfTooSoon is set, this variant is ignored.
@@ -4167,8 +4186,7 @@ typedef enum
#define JET_paramEnableShrinkDatabase 184 // Release space back to the OS when deleting data. This may require an OS feature of Sparse Files, and is subject to change.
// end_PubEsent
-// DEPRECATED: this was once used in the first implementation of DB shrink.
-// #define JET_paramAutomaticShrinkDatabaseFreeSpaceThreshold 185 // DEPRECATED: Minimum threshold (percentage of the database size) that determines if the periodic shrink and/or shrink at JetTerm will take place or not.
+#define JET_paramFlight_CacheTraceSamplingRatio 185 // Trace all cache events for 1 out of JET_paramFlight_CacheTraceSamplingRatio pages.
// begin_PubEsent
@@ -4233,7 +4251,12 @@ typedef enum
#define JET_paramEnableBlockCacheDetach 220 // Indicates that ESE Block Cache detach is enabled. This will allow a file cached by the ESE Block Cache to be detached on open.
-#define JET_paramMaxValueInvalid 221 // This is not a valid parameter. It can change from release to release!
+// end_PubEsent
+#define JET_paramFlight_UseCngAes256Implementation 221 // Whether to use the CNG based implementation (rather than CAPI based one) for AES256 encryption
+#define JET_paramFlight_ContiguousExtentMoveShrinkEnabled 222 // Whether we want to move contiguous pages to a contiguous destination extent during DB Shrink.
+// begin_PubEsent
+
+#define JET_paramMaxValueInvalid 223 // This is not a valid parameter. It can change from release to release!
// end_PubEsent
#if ( JET_VERSION >= 0x0A01 )
@@ -4285,11 +4308,11 @@ typedef enum
typedef struct
{
- unsigned long ulUserID;
- unsigned char nOperationID;
- unsigned char nOperationType;
- unsigned char nClientType;
- unsigned char fFlags;
+ JET_UINT32 ulUserID;
+ JET_BYTE nOperationID;
+ JET_BYTE nOperationType;
+ JET_BYTE nClientType;
+ JET_BYTE fFlags;
} JET_OPERATIONCONTEXT;
#endif // JET_VERSION >= 0x0A00
@@ -4422,6 +4445,11 @@ typedef struct
// end_PubEsent
#define JET_bitForceSessionClosed 0x00000001
+
+ /* Flags for JetDupSession2 */
+
+#define JET_bitDupReadOnlySnapshot 0x00000001 // Duplicate the transaction snapshot point (including transaction context) for readonly transaction.
+ // The new session is returned in level 1 read-only transaction.
// begin_PubEsent
/* Flags for JetAttachDatabase/JetOpenDatabase */
@@ -4752,42 +4780,42 @@ typedef struct
#define bitTableUpdatableDuringRecovery 0x40000000 /* INTERNAL USE ONLY */
// begin_PubEsent
-#define JET_bitTableClassMask 0x001F0000 /* table stats class mask */
-#define JET_bitTableClassNone 0x00000000 /* table belongs to no stats class (default) */
-#define JET_bitTableClass1 0x00010000 /* table belongs to stats class 1 */
-#define JET_bitTableClass2 0x00020000 /* table belongs to stats class 2 */
-#define JET_bitTableClass3 0x00030000 /* table belongs to stats class 3 */
-#define JET_bitTableClass4 0x00040000 /* table belongs to stats class 4 */
-#define JET_bitTableClass5 0x00050000 /* table belongs to stats class 5 */
-#define JET_bitTableClass6 0x00060000 /* table belongs to stats class 6 */
-#define JET_bitTableClass7 0x00070000 /* table belongs to stats class 7 */
-#define JET_bitTableClass8 0x00080000 /* table belongs to stats class 8 */
-#define JET_bitTableClass9 0x00090000 /* table belongs to stats class 9 */
-#define JET_bitTableClass10 0x000A0000 /* table belongs to stats class 10 */
-#define JET_bitTableClass11 0x000B0000 /* table belongs to stats class 11 */
-#define JET_bitTableClass12 0x000C0000 /* table belongs to stats class 12 */
-#define JET_bitTableClass13 0x000D0000 /* table belongs to stats class 13 */
-#define JET_bitTableClass14 0x000E0000 /* table belongs to stats class 14 */
-#define JET_bitTableClass15 0x000F0000 /* table belongs to stats class 15 */
+#define JET_bitTableClassMask 0x001F0000 /* table stats class mask */
+#define JET_bitTableClassNone 0x00000000 /* table belongs to no stats class (default) */
+#define JET_bitTableClass1 0x00010000 /* table belongs to stats class 1 */
+#define JET_bitTableClass2 0x00020000 /* table belongs to stats class 2 */
+#define JET_bitTableClass3 0x00030000 /* table belongs to stats class 3 */
+#define JET_bitTableClass4 0x00040000 /* table belongs to stats class 4 */
+#define JET_bitTableClass5 0x00050000 /* table belongs to stats class 5 */
+#define JET_bitTableClass6 0x00060000 /* table belongs to stats class 6 */
+#define JET_bitTableClass7 0x00070000 /* table belongs to stats class 7 */
+#define JET_bitTableClass8 0x00080000 /* table belongs to stats class 8 */
+#define JET_bitTableClass9 0x00090000 /* table belongs to stats class 9 */
+#define JET_bitTableClass10 0x000A0000 /* table belongs to stats class 10 */
+#define JET_bitTableClass11 0x000B0000 /* table belongs to stats class 11 */
+#define JET_bitTableClass12 0x000C0000 /* table belongs to stats class 12 */
+#define JET_bitTableClass13 0x000D0000 /* table belongs to stats class 13 */
+#define JET_bitTableClass14 0x000E0000 /* table belongs to stats class 14 */
+#define JET_bitTableClass15 0x000F0000 /* table belongs to stats class 15 */
// end_PubEsent
#if ( JET_VERSION >= 0x0A01 )
-#define JET_bitTableClass16 0x00100000 /* table belongs to stats class 16 */
-#define JET_bitTableClass17 0x00110000 /* table belongs to stats class 17 */
-#define JET_bitTableClass18 0x00120000 /* table belongs to stats class 18 */
-#define JET_bitTableClass19 0x00130000 /* table belongs to stats class 19 */
-#define JET_bitTableClass20 0x00140000 /* table belongs to stats class 20 */
-#define JET_bitTableClass21 0x00150000 /* table belongs to stats class 21 */
-#define JET_bitTableClass22 0x00160000 /* table belongs to stats class 22 */
-#define JET_bitTableClass23 0x00170000 /* table belongs to stats class 23 */
-#define JET_bitTableClass24 0x00180000 /* table belongs to stats class 24 */
-#define JET_bitTableClass25 0x00190000 /* table belongs to stats class 25 */
-#define JET_bitTableClass26 0x001A0000 /* table belongs to stats class 26 */
-#define JET_bitTableClass27 0x001B0000 /* table belongs to stats class 27 */
-#define JET_bitTableClass28 0x001C0000 /* table belongs to stats class 28 */
-#define JET_bitTableClass29 0x001D0000 /* table belongs to stats class 29 */
-#define JET_bitTableClass30 0x001E0000 /* table belongs to stats class 30 */
-#define JET_bitTableClass31 0x001F0000 /* table belongs to stats class 31 */
+#define JET_bitTableClass16 0x00100000 /* table belongs to stats class 16 */
+#define JET_bitTableClass17 0x00110000 /* table belongs to stats class 17 */
+#define JET_bitTableClass18 0x00120000 /* table belongs to stats class 18 */
+#define JET_bitTableClass19 0x00130000 /* table belongs to stats class 19 */
+#define JET_bitTableClass20 0x00140000 /* table belongs to stats class 20 */
+#define JET_bitTableClass21 0x00150000 /* table belongs to stats class 21 */
+#define JET_bitTableClass22 0x00160000 /* table belongs to stats class 22 */
+#define JET_bitTableClass23 0x00170000 /* table belongs to stats class 23 */
+#define JET_bitTableClass24 0x00180000 /* table belongs to stats class 24 */
+#define JET_bitTableClass25 0x00190000 /* table belongs to stats class 25 */
+#define JET_bitTableClass26 0x001A0000 /* table belongs to stats class 26 */
+#define JET_bitTableClass27 0x001B0000 /* table belongs to stats class 27 */
+#define JET_bitTableClass28 0x001C0000 /* table belongs to stats class 28 */
+#define JET_bitTableClass29 0x001D0000 /* table belongs to stats class 29 */
+#define JET_bitTableClass30 0x001E0000 /* table belongs to stats class 30 */
+#define JET_bitTableClass31 0x001F0000 /* table belongs to stats class 31 */
#endif // JET_VERSION >= 0x0A01
// begin_PubEsent
@@ -4864,7 +4892,7 @@ typedef struct
#if ( JET_VERSION >= 0x0601 )
- /* Space Hint Flags / JET_SPACEHINTS */
+ /* Space Hint Flags / JET_SPACEHINTS */
// Generic
#define JET_bitSpaceHintsUtilizeParentSpace 0x00000001 // This changes the internal allocation policy to get space hierarchically from a B-Tree's immediate parent.
@@ -4895,28 +4923,28 @@ typedef struct
typedef struct
{
JET_COLUMNID columnid;
- const void *pvData;
- unsigned long cbData;
+ JET_PCVOID pvData;
+ JET_UINT32 cbData;
JET_GRBIT grbit;
- unsigned long ibLongValue;
- unsigned long itagSequence;
+ JET_UINT32 ibLongValue;
+ JET_UINT32 itagSequence;
JET_ERR err;
} JET_SETCOLUMN;
#if ( JET_VERSION >= 0x0501 )
typedef struct
{
- unsigned long paramid;
+ JET_UINT32 paramid;
JET_API_PTR lParam;
- const char *sz;
+ JET_PCSTR sz;
JET_ERR err;
} JET_SETSYSPARAM_A;
typedef struct
{
- unsigned long paramid;
+ JET_UINT32 paramid;
JET_API_PTR lParam;
- const WCHAR *sz;
+ JET_PCWSTR sz;
JET_ERR err;
} JET_SETSYSPARAM_W;
@@ -4986,9 +5014,9 @@ typedef struct
// end_PubEsent
#define JET_bitRetrieveLongId 0x00000040
#define JET_bitRetrieveLongValueRefCount 0x00000080 /* for testing use only */
-// #define JET_bitRetrieveSLVAsSLVInfo 0x00000100 /* internal use only */
+// #define JET_bitRetrieveSLVAsSLVInfo 0x00000100 /* internal use only */
- /* Flags for JetRetrieveColumn when the SLV Provider is enabled */
+ /* Flags for JetRetrieveColumn when the SLV Provider is enabled */
// #define JET_bitRetrieveSLVAsSLVFile 0x00000200 /* retrieve SLV as an SLV File handle */
// #define JET_bitRetrieveSLVAsSLVEA 0x00000400 /* retrieve SLV as an SLV EA list */
@@ -5032,12 +5060,12 @@ typedef struct
typedef struct
{
JET_COLUMNID columnid;
- void *pvData;
- unsigned long cbData;
- unsigned long cbActual;
+ JET_PVOID pvData;
+ JET_UINT32 cbData;
+ JET_UINT32 cbActual;
JET_GRBIT grbit;
- unsigned long ibLongValue;
- unsigned long itagSequence;
+ JET_UINT32 ibLongValue;
+ JET_UINT32 itagSequence;
JET_COLUMNID columnidNextTagged;
JET_ERR err;
} JET_RETRIEVECOLUMN;
@@ -5047,17 +5075,17 @@ typedef struct
typedef struct
{
JET_COLUMNID columnid;
- unsigned short cMultiValues;
+ JET_UINT16 cMultiValues;
union
{
- unsigned short usFlags;
+ JET_UINT16 usFlags;
struct
{
- unsigned short fLongValue:1; // is column LongText/Binary?
- unsigned short fDefaultValue:1; // was a default value retrieved?
- unsigned short fNullOverride:1; // was there an explicit null to override a default value?
- unsigned short fDerived:1; // was column derived from template table?
+ JET_UINT16 fLongValue:1; // is column LongText/Binary?
+ JET_UINT16 fDefaultValue:1; // was a default value retrieved?
+ JET_UINT16 fNullOverride:1; // was there an explicit null to override a default value?
+ JET_UINT16 fDerived:1; // was column derived from template table?
};
};
} JET_RETRIEVEMULTIVALUECOUNT;
@@ -5093,16 +5121,16 @@ typedef struct
typedef struct
{
JET_COLUMNID columnid;
- unsigned long ctagSequence;
- unsigned long* rgtagSequence;
+ JET_UINT32 ctagSequence;
+ JET_UINT32 * rgtagSequence;
} JET_ENUMCOLUMNID;
typedef struct
{
- unsigned long itagSequence;
+ JET_UINT32 itagSequence;
JET_ERR err;
- unsigned long cbData;
- void* pvData;
+ JET_UINT32 cbData;
+ JET_PVOID pvData;
} JET_ENUMCOLUMNVALUE;
typedef struct
@@ -5111,25 +5139,25 @@ typedef struct
JET_ERR err;
union
{
- struct /* err != JET_wrnColumnSingleValue */
+ struct // err != JET_wrnColumnSingleValue
{
- unsigned long cEnumColumnValue;
+ JET_UINT32 cEnumColumnValue;
JET_ENUMCOLUMNVALUE* rgEnumColumnValue;
};
- struct /* err == JET_wrnColumnSingleValue */
+ struct // err == JET_wrnColumnSingleValue
{
- unsigned long cbData;
- void* pvData;
+ JET_UINT32 cbData;
+ JET_PVOID pvData;
};
};
} JET_ENUMCOLUMN;
/* Realloc callback for JetEnumerateColumns */
-typedef void* (JET_API *JET_PFNREALLOC)(
- _In_opt_ void * pvContext,
- _In_opt_ void * pv,
- _In_ unsigned long cb );
+typedef JET_PVOID (JET_API * JET_PFNREALLOC)(
+ _In_opt_ JET_PVOID pvContext,
+ _In_opt_ JET_PVOID pv,
+ _In_ JET_UINT32 cb );
#endif // JET_VERSION >= 0x0501
@@ -5164,14 +5192,14 @@ typedef void* (JET_API *JET_PFNREALLOC)(
typedef struct
{
- unsigned __int64 cbData; // user data in record
- unsigned __int64 cbLongValueData; // user data associated with the record but stored in the long-value tree (NOTE: does NOT count intrinsic long-values)
- unsigned __int64 cbOverhead; // record overhead
- unsigned __int64 cbLongValueOverhead; // overhead of long-value data (NOTE: does not count intrinsic long-values)
- unsigned __int64 cNonTaggedColumns; // total number of fixed/variable columns
- unsigned __int64 cTaggedColumns; // total number of tagged columns
- unsigned __int64 cLongValues; // total number of values stored in the long-value tree for this record (NOTE: does NOT count intrinsic long-values)
- unsigned __int64 cMultiValues; // total number of values beyond the first for each column in the record
+ JET_UINT64 cbData; // user data in record
+ JET_UINT64 cbLongValueData; // user data associated with the record but stored in the long-value tree (NOTE: does NOT count intrinsic long-values)
+ JET_UINT64 cbOverhead; // record overhead
+ JET_UINT64 cbLongValueOverhead; // overhead of long-value data (NOTE: does not count intrinsic long-values)
+ JET_UINT64 cNonTaggedColumns; // total number of fixed/variable columns
+ JET_UINT64 cTaggedColumns; // total number of tagged columns
+ JET_UINT64 cLongValues; // total number of values stored in the long-value tree for this record (NOTE: does NOT count intrinsic long-values)
+ JET_UINT64 cMultiValues; // total number of values beyond the first for each column in the record
} JET_RECSIZE;
#endif // JET_VERSION >= 0x0600
@@ -5180,14 +5208,14 @@ typedef struct
#if ( JET_VERSION >= 0x0600 )
typedef struct tagJET_PAGEINFO
{
- unsigned long pgno; // pgno for the page. must be passed in
- unsigned long fPageIsInitialized:1; // false if the page is zeroed
- unsigned long fCorrectableError:1; // correctable error found on page
- unsigned __int64 checksumActual; // checksum stored on the page
- unsigned __int64 checksumExpected; // checksum expected for the page
- unsigned __int64 dbtime; // dbtime on the page
- unsigned __int64 structureChecksum; // checksum of the page structure
- unsigned __int64 flags; // currently unused
+ JET_UINT32 pgno; // pgno for the page. must be passed in
+ JET_UINT32 fPageIsInitialized:1; // false if the page is zeroed
+ JET_UINT32 fCorrectableError:1; // correctable error found on page
+ JET_UINT64 checksumActual; // checksum stored on the page
+ JET_UINT64 checksumExpected; // checksum expected for the page
+ JET_UINT64 dbtime; // dbtime on the page
+ JET_UINT64 structureChecksum; // checksum of the page structure
+ JET_UINT64 flags; // currently unused
} JET_PAGEINFO;
#endif // JET_VERSION >= 0x0600
@@ -5195,38 +5223,38 @@ typedef struct tagJET_PAGEINFO
#if ( JET_VERSION >= 0x0601 )
typedef struct
{
- unsigned __int64 cbData; // user data in record
- unsigned __int64 cbLongValueData; // user data associated with the record but stored in the long-value tree (NOTE: does NOT count intrinsic long-values)
- unsigned __int64 cbOverhead; // record overhead
- unsigned __int64 cbLongValueOverhead; // overhead of long-value data (NOTE: does not count intrinsic long-values)
- unsigned __int64 cNonTaggedColumns; // total number of fixed/variable columns
- unsigned __int64 cTaggedColumns; // total number of tagged columns
- unsigned __int64 cLongValues; // total number of values stored in the long-value tree for this record (NOTE: does NOT count intrinsic long-values)
- unsigned __int64 cMultiValues; // total number of values beyond the first for each column in the record
- unsigned __int64 cCompressedColumns; // total number of columns which are compressed
- unsigned __int64 cbDataCompressed; // compressed size of user data in record (same as cbData if no intrinsic long-values are compressed)
- unsigned __int64 cbLongValueDataCompressed; // compressed size of user data in the long-value tree (same as cbLongValue data if no separated long values are compressed)
+ JET_UINT64 cbData; // user data in record
+ JET_UINT64 cbLongValueData; // user data associated with the record but stored in the long-value tree (NOTE: does NOT count intrinsic long-values)
+ JET_UINT64 cbOverhead; // record overhead
+ JET_UINT64 cbLongValueOverhead; // overhead of long-value data (NOTE: does not count intrinsic long-values)
+ JET_UINT64 cNonTaggedColumns; // total number of fixed/variable columns
+ JET_UINT64 cTaggedColumns; // total number of tagged columns
+ JET_UINT64 cLongValues; // total number of values stored in the long-value tree for this record (NOTE: does NOT count intrinsic long-values)
+ JET_UINT64 cMultiValues; // total number of values beyond the first for each column in the record
+ JET_UINT64 cCompressedColumns; // total number of columns which are compressed
+ JET_UINT64 cbDataCompressed; // compressed size of user data in record (same as cbData if no intrinsic long-values are compressed)
+ JET_UINT64 cbLongValueDataCompressed; // compressed size of user data in the long-value tree (same as cbLongValue data if no separated long values are compressed)
} JET_RECSIZE2;
#endif // JET_VERSION >= 0x0601
// end_PubEsent
#if ( JET_VERSION >= 0x0A01 )
typedef struct
{
- unsigned __int64 cbData; // user data in record
- unsigned __int64 cbLongValueData; // user data associated with the record but stored in the long-value tree (NOTE: does NOT count intrinsic long-values)
- unsigned __int64 cbOverhead; // record overhead
- unsigned __int64 cbLongValueOverhead; // overhead of long-value data (NOTE: does not count intrinsic long-values)
- unsigned __int64 cNonTaggedColumns; // total number of fixed/variable columns
- unsigned __int64 cTaggedColumns; // total number of tagged columns
- unsigned __int64 cLongValues; // total number of values stored in the long-value tree for this record (NOTE: does NOT count intrinsic long-values)
- unsigned __int64 cMultiValues; // total number of values beyond the first for each column in the record
- unsigned __int64 cCompressedColumns; // total number of columns which are compressed
- unsigned __int64 cbDataCompressed; // compressed size of user data in record (same as cbData if no intrinsic long-values are compressed)
- unsigned __int64 cbLongValueDataCompressed; // compressed size of user data in the long-value tree (same as cbLongValue data if no separated long values are compressed)
- unsigned __int64 cbIntrinsicLongValueData; // user data stored in intrinsic LVs (in the record).
- unsigned __int64 cbIntrinsicLongValueDataCompressed; // compressed size of user data stored in intrinsic LVs (in the record).
- unsigned __int64 cIntrinsicLongValues; // total number of intrinsic LVs stored in the record.
- unsigned __int64 cbKey; // Key size in bytes. Doesn't include storage overhead. Does include key normalization overhead.
+ JET_UINT64 cbData; // user data in record
+ JET_UINT64 cbLongValueData; // user data associated with the record but stored in the long-value tree (NOTE: does NOT count intrinsic long-values)
+ JET_UINT64 cbOverhead; // record overhead
+ JET_UINT64 cbLongValueOverhead; // overhead of long-value data (NOTE: does not count intrinsic long-values)
+ JET_UINT64 cNonTaggedColumns; // total number of fixed/variable columns
+ JET_UINT64 cTaggedColumns; // total number of tagged columns
+ JET_UINT64 cLongValues; // total number of values stored in the long-value tree for this record (NOTE: does NOT count intrinsic long-values)
+ JET_UINT64 cMultiValues; // total number of values beyond the first for each column in the record
+ JET_UINT64 cCompressedColumns; // total number of columns which are compressed
+ JET_UINT64 cbDataCompressed; // compressed size of user data in record (same as cbData if no intrinsic long-values are compressed)
+ JET_UINT64 cbLongValueDataCompressed; // compressed size of user data in the long-value tree (same as cbLongValue data if no separated long values are compressed)
+ JET_UINT64 cbIntrinsicLongValueData; // user data stored in intrinsic LVs (in the record).
+ JET_UINT64 cbIntrinsicLongValueDataCompressed; // compressed size of user data stored in intrinsic LVs (in the record).
+ JET_UINT64 cIntrinsicLongValues; // total number of intrinsic LVs stored in the record.
+ JET_UINT64 cbKey; // Key size in bytes. Doesn't include storage overhead. Does include key normalization overhead.
} JET_RECSIZE3;
#endif // JET_VERSION >= 0x0A01
@@ -5235,8 +5263,8 @@ typedef struct
typedef struct tagJET_PAGEINFO2
{
JET_PAGEINFO pageInfo;
- unsigned __int64 rgChecksumActual[ 3 ]; // more checksum stored on the page
- unsigned __int64 rgChecksumExpected[ 3]; // more checksum expected for the page
+ JET_UINT64 rgChecksumActual[ 3 ]; // more checksum stored on the page
+ JET_UINT64 rgChecksumExpected[ 3]; // more checksum expected for the page
} JET_PAGEINFO2;
#endif // JET_VERSION >= 0x0601
@@ -5293,7 +5321,7 @@ typedef struct tagJET_PAGEINFO2
#define JET_bitCopySnapshot 0x00000002 /* bit 1: normal (0) or copy (1) snapshot */
#define JET_bitContinueAfterThaw 0x00000004 /* bit 2: end on thaw (0) or wait for [truncate +] end snapshot */
#if ( JET_VERSION >= 0x0601 )
-#define JET_bitExplicitPrepare 0x00000008 /* bit 3: all instaces prepared by default (0) or no instance prepared by default (1) */
+#define JET_bitExplicitPrepare 0x00000008 /* bit 3: all instaces prepared by default (0) or no instance prepared by default (1) */
#endif // JET_VERSION >= 0x0601
/* Flags for JetOSSnapshotTruncateLog & JetOSSnapshotTruncateLogInstance */
@@ -5318,13 +5346,13 @@ typedef struct tagJET_PAGEINFO2
typedef struct tag_JET_EMITDATACTX
{
- unsigned long cbStruct;
- unsigned long dwVersion;
- unsigned __int64 qwSequenceNum;
+ JET_UINT32 cbStruct;
+ JET_UINT32 dwVersion;
+ JET_UINT64 qwSequenceNum;
JET_GRBIT grbitOperationalFlags;
JET_LOGTIME logtimeEmit;
JET_LGPOS lgposLogData;
- unsigned long cbLogData;
+ JET_UINT32 cbLogData;
} JET_EMITDATACTX;
// 40 bytes
@@ -5333,9 +5361,9 @@ typedef struct tag_JET_EMITDATACTX
typedef JET_ERR (JET_API * JET_PFNEMITLOGDATA)(
_In_ JET_INSTANCE instance,
_In_ JET_EMITDATACTX * pEmitLogDataCtx,
- _In_ void * pvLogData,
- _In_ unsigned long cbLogData,
- _In_ void * callbackCtx );
+ _In_ JET_PVOID pvLogData,
+ _In_ JET_UINT32 cbLogData,
+ _In_ JET_PVOID callbackCtx );
#endif // JET_VERSION >= 0x0601
@@ -5498,7 +5526,7 @@ typedef JET_ERR (JET_API * JET_PFNEMITLOGDATA)(
// Windows 10
#if ( JET_VERSION >= 0x0A00 )
-#define JET_coltypUnsignedLongLong 18 /* 8-byte unsigned integer */
+#define JET_coltypUnsignedLongLong 18 /* 8-byte unsigned integer */
#define JET_coltypMax 19 /* the number of column types */
/* used for validity tests and */
/* array declarations. */
@@ -5805,7 +5833,7 @@ typedef JET_ERR (JET_API * JET_PFNEMITLOGDATA)(
#define JET_ExceptionFailFast 0x0004 /* Use the Windows RaiseFailFastException API to force a crash */
// end_PubEsent
- /* AssertAction / JET_paramAssertAction */
+ /* AssertAction / JET_paramAssertAction */
#define JET_AssertExit 0x0000 /* Exit the application */
#define JET_AssertBreak 0x0001 /* Break to debugger */
@@ -5957,36 +5985,36 @@ typedef JET_ERR (JET_API * JET_PFNEMITLOGDATA)(
// BUFFER MANAGER errors
//
// end_PubEsent
-#define wrnBFCacheMiss 200 /* ese97,esent only: page latch caused a cache miss */
-#define errBFPageNotCached -201 /* page is not cached */
-#define errBFLatchConflict -202 /* page latch conflict */
-#define errBFPageCached -203 /* page is cached */
-#define wrnBFPageFlushPending 204 /* page is currently being written */
-#define wrnBFPageFault 205 /* page latch caused a page fault */
-#define wrnBFBadLatchHint 206 /* page latch hint was incorrect */
-#define wrnBFLatchMaintConflict 207 /* page latch conflict with foreground maintenance */
-#define wrnBFIWriteIOComplete 208 /* signal a successful write IO from the async IO completion function */
-
-#define errBFIPageEvicted -250 /* ese97,esent only: page evicted from the cache */
-#define errBFIPageCached -251 /* ese97,esent only: page already cached */
-#define errBFIOutOfOLPs -252 /* ese97,esent only: out of OLPs */
-#define errBFIOutOfBatchIOBuffers -253 /* out of Batch I/O (Opportune write) Buffers */
-#define errBFINoBufferAvailable -254 /* no buffer available for immediate use */
+#define wrnBFCacheMiss 200 /* ese97,esent only: page latch caused a cache miss */
+#define errBFPageNotCached -201 /* page is not cached */
+#define errBFLatchConflict -202 /* page latch conflict */
+#define errBFPageCached -203 /* page is cached */
+#define wrnBFPageFlushPending 204 /* page is currently being written */
+#define wrnBFPageFault 205 /* page latch caused a page fault */
+#define wrnBFBadLatchHint 206 /* page latch hint was incorrect */
+#define wrnBFLatchMaintConflict 207 /* page latch conflict with foreground maintenance */
+#define wrnBFIWriteIOComplete 208 /* signal a successful write IO from the async IO completion function */
+
+#define errBFIPageEvicted -250 /* ese97,esent only: page evicted from the cache */
+#define errBFIPageCached -251 /* ese97,esent only: page already cached */
+#define errBFIOutOfOLPs -252 /* ese97,esent only: out of OLPs */
+#define errBFIOutOfBatchIOBuffers -253 /* out of Batch I/O (Opportune write) Buffers */
+#define errBFINoBufferAvailable -254 /* no buffer available for immediate use */
// begin_PubEsent
#define JET_errDatabaseBufferDependenciesCorrupted -255 /* Buffer dependencies improperly set. Recovery failure */
// end_PubEsent
-#define errBFIRemainingDependencies -256 /* dependencies remain on this buffer */
-#define errBFIPageFlushPending -257 /* page is currently being written */
+#define errBFIRemainingDependencies -256 /* dependencies remain on this buffer */
+#define errBFIPageFlushPending -257 /* page is currently being written */
#define errBFIPageDirty -258 /* the page could not be evicted from the cache because it or its versions were not clean enough */
-#define errBFIPageFlushed -259 /* page write initiated */
-#define errBFIPageFaultPending -260 /* page is currently being read */
-#define errBFIPageNotVerified -261 /* page data has not been verified */
-#define errBFIDependentPurged -262 /* page cannot be flushed due to purged dependencies */
-#define errBFIPageFlushDisallowedOnIOThread -263 /* the page couldn't be written because ErrBFIFlushPage is being called from the I/O thread */
+#define errBFIPageFlushed -259 /* page write initiated */
+#define errBFIPageFaultPending -260 /* page is currently being read */
+#define errBFIPageNotVerified -261 /* page data has not been verified */
+#define errBFIDependentPurged -262 /* page cannot be flushed due to purged dependencies */
+#define errBFIPageFlushDisallowedOnIOThread -263 /* the page couldn't be written because ErrBFIFlushPage is being called from the I/O thread */
#define errBFIPageTouchTooRecent -264 /* the page could not be flushed because a recent page touch would offend the waypoint */
#define errBFICheckpointWorkRemaining -266 /* checkpoint depth maintenance is not finished due to page flushes or dependency flushes remaining */
#define errBFIPageRemapNotReVerified -267 /* page is remapped after a write, which means it needs to be reverified */
-#define errBFIReqSyncFlushMapWriteFailed -268 /* UNUSED: required synchronous write to the flush map failed */
+#define errBFIReqSyncFlushMapWriteFailed -268 /* UNUSED: required synchronous write to the flush map failed */
#define errBFIPageFlushPendingHungIO -269 /* page is currently being written and the write I/O is hung */
#define errBFIPageFaultPendingHungIO -270 /* page is currently being read and the read I/O is hung */
#define errBFIPageFlushPendingSlowIO -271 /* page is currently being written and the write I/O is slow */
@@ -6048,7 +6076,7 @@ typedef JET_ERR (JET_API * JET_PFNEMITLOGDATA)(
// begin_PubEsent
#define JET_errNTSystemCallFailed -334 // A call to the operating system failed
// end_PubEsent
-#define wrnBTShallowTree 335 // BTree is only one or two levels deep
+#define errBTShallowTree -335 // BTree is only one or two levels deep
#define errBTMergeNotSynchronous -336 // Multiple threads attempting to perform merge/split on same page (likely OLD vs. RCEClean)
#define wrnSPReservedPages 337 // space manager reserved pages for future space tree splits
// begin_PubEsent
@@ -6081,6 +6109,15 @@ typedef JET_ERR (JET_API * JET_PFNEMITLOGDATA)(
// begin_PubEsent
#define JET_errPageTagCorrupted -357 // A tag / line on page is logically corrupted, offset or size is bad, or tag count on page is bad.
#define JET_errNodeCorrupted -358 // A node or prefix node is logically corrupted, the key suffix size is larger than the node or line's size.
+// end_PubEsent
+#define errBBTBuffFull -359 /* BBT Buffer is full */
+#define errBBTNodeNotFound -360 /* Node not found in the BBT buffer */
+#define errBBTCurrencyLost -361 /* Currency on the BBT buffer couldn't be re-established */
+#define wrnBBTMergeTargetFull 362 /* Couldn't merge all the external nodes during a BBT evict operation. */
+#define wrnBBTPathUnvisitedNode 363 /* ErrBBTNextPath() / ErrBBTPrevPath() didn't switch paths because the currency should move first to an unvisited node in the current path.*/
+// begin_PubEsent
+#define JET_errBBTNodeCorrupted -364 /* A property of the BBT node is logically corrupted. Or the BBT node isn't valid. */
+#define JET_errBBTBuffCorrupted -365 /* A BBT buff is logically corrupted. The nodes are out of sequence or the BBT header is corrupt. */
/* RECORD MANAGER errors
/**/
@@ -6464,7 +6501,7 @@ typedef JET_ERR (JET_API * JET_PFNEMITLOGDATA)(
// begin_PubEsent
#define JET_errDatabaseNotReady -1230 /* Recovery on this database has not yet completed enough to permit access. */
-#define JET_errDatabaseAttachedForRecovery -1231 /* Database is attached but only for recovery. It must be explicitly attached before it can be opened. */
+#define JET_errDatabaseAttachedForRecovery -1231 /* Database is attached but only for recovery. It must be explicitly attached before it can be opened. */
#define JET_errTransactionsNotReadyDuringRecovery -1232 /* Recovery has not seen any Begin0/Commit0 records and so does not know what trxBegin0 to assign to this transaction */
@@ -6674,6 +6711,7 @@ typedef JET_ERR (JET_API * JET_PFNEMITLOGDATA)(
#define errRBSCorruptUninitializedRBSRemoved -1946 /* The RBS being loaded is either missing or corrupt and uninitialized, so it has been removed. */
#define JET_errRBSRedeleteFDPUnexpected -1947 /* Indicates that the reverted table marked with delete flag is unexpected. */
#define JET_errRBSRCPageFDPDeleteFileCorrupt -1948 /* The database cannot be reverted to the expected time as we are in apply root page records state but the corresponding file to init the page state is corrupt */
+#define JET_errRBSRedeleteFDPExpected -1949 /* Indicates that the reverted table is expected to be marked with delete flag. */
// begin_PubEsent
#define JET_wrnDefragAlreadyRunning 2000 /* Online defrag already running on specified database */
@@ -6936,10 +6974,10 @@ JetCreateInstance2W(
JET_ERR JET_API
JetGetInstanceMiscInfo(
- _In_ JET_INSTANCE instance,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_INSTANCE instance,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7039,7 +7077,7 @@ JET_ERR JET_API
JetSetSystemParameterA(
_Inout_opt_ JET_INSTANCE * pinstance,
_In_opt_ JET_SESID sesid,
- _In_ unsigned long paramid,
+ _In_ JET_UINT32 paramid,
_In_opt_ JET_API_PTR lParam,
_In_opt_ JET_PCSTR szParam );
@@ -7055,7 +7093,7 @@ JET_ERR JET_API
JetSetSystemParameterW(
_Inout_opt_ JET_INSTANCE * pinstance,
_In_opt_ JET_SESID sesid,
- _In_ unsigned long paramid,
+ _In_ JET_UINT32 paramid,
_In_opt_ JET_API_PTR lParam,
_In_opt_ JET_PCWSTR szParam );
@@ -7080,10 +7118,10 @@ JET_ERR JET_API
JetGetSystemParameterA(
_In_ JET_INSTANCE instance,
_In_opt_ JET_SESID sesid,
- _In_ unsigned long paramid,
+ _In_ JET_UINT32 paramid,
_Out_opt_ JET_API_PTR * plParam,
_Out_writes_bytes_opt_( cbMax ) JET_PSTR szParam,
- _In_ unsigned long cbMax );
+ _In_ JET_UINT32 cbMax );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7097,10 +7135,10 @@ JET_ERR JET_API
JetGetSystemParameterW(
_In_ JET_INSTANCE instance,
_In_opt_ JET_SESID sesid,
- _In_ unsigned long paramid,
+ _In_ JET_UINT32 paramid,
_Out_opt_ JET_API_PTR * plParam,
_Out_writes_bytes_opt_( cbMax ) JET_PWSTR szParam,
- _In_ unsigned long cbMax );
+ _In_ JET_UINT32 cbMax );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7121,17 +7159,17 @@ JetGetSystemParameterW(
JET_ERR JET_API
JetSetResourceParam(
- _In_ JET_INSTANCE instance,
- _In_ JET_RESOPER resoper,
- _In_ JET_RESID resid,
- _In_ JET_API_PTR ulParam );
+ _In_ JET_INSTANCE instance,
+ _In_ JET_RESOPER resoper,
+ _In_ JET_RESID resid,
+ _In_ JET_API_PTR ulParam );
JET_ERR JET_API
JetGetResourceParam(
- _In_ JET_INSTANCE instance,
- _In_ JET_RESOPER resoper,
- _In_ JET_RESID resid,
- _Out_ JET_API_PTR* pulParam );
+ _In_ JET_INSTANCE instance,
+ _In_ JET_RESOPER resoper,
+ _In_ JET_RESID resid,
+ _Out_ JET_API_PTR * pulParam );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -7151,8 +7189,8 @@ JetGetResourceParam(
JET_ERR JET_API
JetEnableMultiInstanceA(
_In_reads_opt_( csetsysparam ) JET_SETSYSPARAM_A * psetsysparam,
- _In_ unsigned long csetsysparam,
- _Out_opt_ unsigned long * pcsetsucceed );
+ _In_ JET_UINT32 csetsysparam,
+ _Out_opt_ JET_UINT32 * pcsetsucceed );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7165,8 +7203,8 @@ JetEnableMultiInstanceA(
JET_ERR JET_API
JetEnableMultiInstanceW(
_In_reads_opt_( csetsysparam ) JET_SETSYSPARAM_W * psetsysparam,
- _In_ unsigned long csetsysparam,
- _Out_opt_ unsigned long * pcsetsucceed );
+ _In_ JET_UINT32 csetsysparam,
+ _Out_opt_ JET_UINT32 * pcsetsucceed );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7187,14 +7225,14 @@ JetEnableMultiInstanceW(
JET_ERR JET_API
JetResetCounter(
- _In_ JET_SESID sesid,
- _In_ long CounterType );
+ _In_ JET_SESID sesid,
+ _In_ JET_INT32 CounterType );
JET_ERR JET_API
JetGetCounter(
- _In_ JET_SESID sesid,
- _In_ long CounterType,
- _Out_ long * plValue );
+ _In_ JET_SESID sesid,
+ _In_ JET_INT32 CounterType,
+ _Out_ JET_INT32 * plValue );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -7208,8 +7246,8 @@ JetGetCounter(
JET_ERR JET_API
JetGetThreadStats(
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax );
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7276,6 +7314,13 @@ JetEndSession(
#pragma endregion
// end_PubEsent
+
+JET_ERR JET_API
+JetDupSession2(
+ _In_ JET_SESID sesid,
+ _In_ JET_GRBIT grbit,
+ _Out_ JET_SESID * psesid );
+
#if ( JET_VERSION >= 0x0600 )
#pragma region Desktop Family
@@ -7283,10 +7328,10 @@ JetEndSession(
JET_ERR JET_API
JetGetSessionInfo(
- _In_ JET_SESID sesid,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ const unsigned long cbMax,
- _In_ const unsigned long ulInfoLevel );
+ _In_ JET_SESID sesid,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ const JET_UINT32 cbMax,
+ _In_ const JET_UINT32 ulInfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -7301,7 +7346,7 @@ JetGetSessionInfo(
JET_ERR JET_API
JetGetVersion(
_In_ JET_SESID sesid,
- _Out_ unsigned long * pwVersion );
+ _Out_ JET_UINT32 * pwVersion );
JET_ERR JET_API
JetIdle(
@@ -7359,16 +7404,6 @@ JetIdle(
// shrinking the database, but avoids a potential small extra
// cost afterwards, when operating on the shrunk database.
-#define JET_bitShrinkDatabaseDontMoveRootsOnAttach 0x00000004 // Disable root moves when shrinking the database
- // at attachment time. NOTE: temporary, for flighting only.
-
-#define JET_bitShrinkDatabaseDontTruncateLeakedPagesOnAttach 0x00000008 // Disable truncating leaked pages when shrinking the database
- // at attachment time. NOTE: temporary, for flighting only.
-
-#define JET_bitShrinkDatabaseDontTruncateIndeterminatePagesOnAttach 0x00000010 // Disable truncating indeterminate/uncategorized pages when
- // shrinking the database at attachment time.
- // NOTE: temporary, for flighting only.
-
#endif // JET_VERSION >= 0x0A01
// begin_PubEsent
@@ -7426,7 +7461,7 @@ JET_ERR JET_API
JetCreateDatabase2A(
_In_ JET_SESID sesid,
_In_ JET_PCSTR szFilename,
- _In_ const unsigned long cpgDatabaseSizeMax,
+ _In_ const JET_UINT32 cpgDatabaseSizeMax,
_Out_ JET_DBID * pdbid,
_In_ JET_GRBIT grbit );
@@ -7441,7 +7476,7 @@ JetCreateDatabase2A(
JET_ERR JET_API JetCreateDatabase2W(
_In_ JET_SESID sesid,
_In_ JET_PCWSTR szFilename,
- _In_ const unsigned long cpgDatabaseSizeMax,
+ _In_ const JET_UINT32 cpgDatabaseSizeMax,
_Out_ JET_DBID * pdbid,
_In_ JET_GRBIT grbit );
@@ -7467,7 +7502,7 @@ JET_ERR JET_API JetCreateDatabase3A(
_In_ JET_PCSTR szFilename,
_Out_ JET_DBID * pdbid,
_In_reads_opt_( csetdbparam ) JET_SETDBPARAM * rgsetdbparam,
- _In_ unsigned long csetdbparam,
+ _In_ JET_UINT32 csetdbparam,
_In_ JET_GRBIT grbit );
JET_ERR JET_API JetCreateDatabase3W(
@@ -7475,7 +7510,7 @@ JET_ERR JET_API JetCreateDatabase3W(
_In_ JET_PCWSTR szFilename,
_Out_ JET_DBID * pdbid,
_In_reads_opt_( csetdbparam ) JET_SETDBPARAM * rgsetdbparam,
- _In_ unsigned long csetdbparam,
+ _In_ JET_UINT32 csetdbparam,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
@@ -7538,7 +7573,7 @@ JET_ERR JET_API
JetAttachDatabase2A(
_In_ JET_SESID sesid,
_In_ JET_PCSTR szFilename,
- _In_ const unsigned long cpgDatabaseSizeMax,
+ _In_ const JET_UINT32 cpgDatabaseSizeMax,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
@@ -7553,7 +7588,7 @@ JET_ERR JET_API
JetAttachDatabase2W(
_In_ JET_SESID sesid,
_In_ JET_PCWSTR szFilename,
- _In_ const unsigned long cpgDatabaseSizeMax,
+ _In_ const JET_UINT32 cpgDatabaseSizeMax,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
@@ -7578,7 +7613,7 @@ JetAttachDatabase3A(
_In_ JET_SESID sesid,
_In_ JET_PCSTR szFilename,
_In_reads_opt_( csetdbparam ) JET_SETDBPARAM * rgsetdbparam,
- _In_ unsigned long csetdbparam,
+ _In_ JET_UINT32 csetdbparam,
_In_ JET_GRBIT grbit );
JET_ERR JET_API
@@ -7586,7 +7621,7 @@ JetAttachDatabase3W(
_In_ JET_SESID sesid,
_In_ JET_PCWSTR szFilename,
_In_reads_opt_( csetdbparam ) JET_SETDBPARAM * rgsetdbparam,
- _In_ unsigned long csetdbparam,
+ _In_ JET_UINT32 csetdbparam,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
@@ -7686,14 +7721,14 @@ JetDetachDatabase2W(
JET_ERR JET_API
JetGetObjectInfoA(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_OBJTYP objtyp,
- _In_opt_ JET_PCSTR szContainerName,
- _In_opt_ JET_PCSTR szObjectName,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_OBJTYP objtyp,
+ _In_opt_ JET_PCSTR szContainerName,
+ _In_opt_ JET_PCSTR szObjectName,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7705,14 +7740,14 @@ JetGetObjectInfoA(
JET_ERR JET_API
JetGetObjectInfoW(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_OBJTYP objtyp,
- _In_opt_ JET_PCWSTR szContainerName,
- _In_opt_ JET_PCWSTR szObjectName,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_OBJTYP objtyp,
+ _In_opt_ JET_PCWSTR szContainerName,
+ _In_opt_ JET_PCWSTR szObjectName,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7734,11 +7769,11 @@ JetGetObjectInfoW(
JET_ERR JET_API
JetGetTableInfoA(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7750,11 +7785,11 @@ JetGetTableInfoA(
JET_ERR JET_API
JetGetTableInfoW(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7774,20 +7809,20 @@ JetGetTableInfoW(
JET_ERR JET_API
JetSetTableInfoW(
- _In_opt_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_reads_bytes_opt_( cbParam ) const void * pvParam,
- _In_ unsigned long cbParam,
- _In_ unsigned long InfoLevel );
+ _In_opt_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_reads_bytes_opt_( cbParam ) JET_PCVOID pvParam,
+ _In_ JET_UINT32 cbParam,
+ _In_ JET_UINT32 InfoLevel );
JET_ERR JET_API
JetSetTableInfoA(
- _In_opt_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_reads_bytes_opt_( cbParam ) const void * pvParam,
- _In_ unsigned long cbParam,
- _In_ unsigned long InfoLevel );
+ _In_opt_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_reads_bytes_opt_( cbParam ) JET_PCVOID pvParam,
+ _In_ JET_UINT32 cbParam,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7800,10 +7835,10 @@ JetSetTableInfoA(
JET_ERR JET_API
JetCreateEncryptionKey(
- _In_ unsigned long encryptionAlgorithm,
- _Out_writes_bytes_to_opt_( cbKey, *pcbActual ) void * pvKey,
- _In_ unsigned long cbKey,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_UINT32 encryptionAlgorithm,
+ _Out_writes_bytes_to_opt_( cbKey, *pcbActual ) JET_PVOID pvKey,
+ _In_ JET_UINT32 cbKey,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif // JET_VERSION >= 0x0A01
// begin_PubEsent
@@ -7817,12 +7852,12 @@ JetCreateEncryptionKey(
JET_ERR JET_API
JetCreateTableA(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_PCSTR szTableName,
- _In_ unsigned long lPages,
- _In_ unsigned long lDensity,
- _Out_ JET_TABLEID * ptableid );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_PCSTR szTableName,
+ _In_ JET_UINT32 lPages,
+ _In_ JET_UINT32 lDensity,
+ _Out_ JET_TABLEID * ptableid );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7834,12 +7869,12 @@ JetCreateTableA(
JET_ERR JET_API
JetCreateTableW(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_PCWSTR szTableName,
- _In_ unsigned long lPages,
- _In_ unsigned long lDensity,
- _Out_ JET_TABLEID * ptableid );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_PCWSTR szTableName,
+ _In_ JET_UINT32 lPages,
+ _In_ JET_UINT32 lDensity,
+ _Out_ JET_TABLEID * ptableid );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7860,9 +7895,9 @@ JetCreateTableW(
JET_ERR JET_API
JetCreateTableColumnIndexA(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _Inout_ JET_TABLECREATE_A * ptablecreate );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _Inout_ JET_TABLECREATE_A * ptablecreate );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -7874,9 +7909,9 @@ JetCreateTableColumnIndexA(
JET_ERR JET_API
JetCreateTableColumnIndexW(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _Inout_ JET_TABLECREATE_W * ptablecreate );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _Inout_ JET_TABLECREATE_W * ptablecreate );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8128,12 +8163,12 @@ JET_ERR JET_API JetRenameTableW(
JET_ERR JET_API
JetGetTableColumnInfoA(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_opt_ JET_PCSTR szColumnName,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_opt_ JET_PCSTR szColumnName,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8144,12 +8179,12 @@ JetGetTableColumnInfoA(
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT)
JET_ERR JET_API JetGetTableColumnInfoW(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_opt_ JET_PCWSTR szColumnName,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_opt_ JET_PCWSTR szColumnName,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8171,13 +8206,13 @@ JET_ERR JET_API JetGetTableColumnInfoW(
JET_ERR JET_API
JetGetColumnInfoA(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_PCSTR szTableName,
- _In_opt_ JET_PCSTR pColumnNameOrId,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_PCSTR szTableName,
+ _In_opt_ JET_PCSTR pColumnNameOrId,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8188,13 +8223,13 @@ JetGetColumnInfoA(
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT)
JET_ERR JET_API JetGetColumnInfoW(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_PCWSTR szTableName,
- _In_opt_ JET_PCWSTR pwColumnNameOrId,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_PCWSTR szTableName,
+ _In_opt_ JET_PCWSTR pwColumnNameOrId,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8216,13 +8251,13 @@ JET_ERR JET_API JetGetColumnInfoW(
JET_ERR JET_API
JetAddColumnA(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_ JET_PCSTR szColumnName,
- _In_ const JET_COLUMNDEF * pcolumndef,
- _In_reads_bytes_opt_( cbDefault ) const void * pvDefault,
- _In_ unsigned long cbDefault,
- _Out_opt_ JET_COLUMNID * pcolumnid );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_ JET_PCSTR szColumnName,
+ _In_ const JET_COLUMNDEF * pcolumndef,
+ _In_reads_bytes_opt_( cbDefault ) JET_PCVOID pvDefault,
+ _In_ JET_UINT32 cbDefault,
+ _Out_opt_ JET_COLUMNID * pcolumnid );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8233,13 +8268,13 @@ JetAddColumnA(
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT)
JET_ERR JET_API JetAddColumnW(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_ JET_PCWSTR szColumnName,
- _In_ const JET_COLUMNDEF * pcolumndef,
- _In_reads_bytes_opt_( cbDefault ) const void * pvDefault,
- _In_ unsigned long cbDefault,
- _Out_opt_ JET_COLUMNID * pcolumnid );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_ JET_PCWSTR szColumnName,
+ _In_ const JET_COLUMNDEF * pcolumndef,
+ _In_reads_bytes_opt_( cbDefault ) JET_PCVOID pvDefault,
+ _In_ JET_UINT32 cbDefault,
+ _Out_opt_ JET_COLUMNID * pcolumnid );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8386,13 +8421,13 @@ JetRenameColumnW(
JET_ERR JET_API
JetSetColumnDefaultValueA(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_PCSTR szTableName,
- _In_ JET_PCSTR szColumnName,
- _In_reads_bytes_( cbData ) const void * pvData,
- _In_ const unsigned long cbData,
- _In_ const JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_PCSTR szTableName,
+ _In_ JET_PCSTR szColumnName,
+ _In_reads_bytes_( cbData ) JET_PCVOID pvData,
+ _In_ const JET_UINT32 cbData,
+ _In_ const JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8404,13 +8439,13 @@ JetSetColumnDefaultValueA(
JET_ERR JET_API
JetSetColumnDefaultValueW(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_PCWSTR szTableName,
- _In_ JET_PCWSTR szColumnName,
- _In_reads_bytes_( cbData ) const void * pvData,
- _In_ const unsigned long cbData,
- _In_ const JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_PCWSTR szTableName,
+ _In_ JET_PCWSTR szColumnName,
+ _In_reads_bytes_( cbData ) JET_PCVOID pvData,
+ _In_ const JET_UINT32 cbData,
+ _In_ const JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8432,12 +8467,12 @@ JetSetColumnDefaultValueW(
JET_ERR JET_API
JetGetTableIndexInfoA(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_opt_ JET_PCSTR szIndexName,
- _Out_writes_bytes_( cbResult ) void * pvResult,
- _In_ unsigned long cbResult,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_opt_ JET_PCSTR szIndexName,
+ _Out_writes_bytes_( cbResult ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbResult,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8449,12 +8484,12 @@ JetGetTableIndexInfoA(
JET_ERR JET_API
JetGetTableIndexInfoW(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_opt_ JET_PCWSTR szIndexName,
- _Out_writes_bytes_( cbResult ) void * pvResult,
- _In_ unsigned long cbResult,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_opt_ JET_PCWSTR szIndexName,
+ _Out_writes_bytes_( cbResult ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbResult,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8476,13 +8511,13 @@ JetGetTableIndexInfoW(
JET_ERR JET_API
JetGetIndexInfoA(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_PCSTR szTableName,
- _In_opt_ JET_PCSTR szIndexName,
- _Out_writes_bytes_( cbResult ) void * pvResult,
- _In_ unsigned long cbResult,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_PCSTR szTableName,
+ _In_opt_ JET_PCSTR szIndexName,
+ _Out_writes_bytes_( cbResult ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbResult,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8494,13 +8529,13 @@ JetGetIndexInfoA(
JET_ERR JET_API
JetGetIndexInfoW(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_PCWSTR szTableName,
- _In_opt_ JET_PCWSTR szIndexName,
- _Out_writes_bytes_( cbResult ) void * pvResult,
- _In_ unsigned long cbResult,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_PCWSTR szTableName,
+ _In_opt_ JET_PCWSTR szIndexName,
+ _Out_writes_bytes_( cbResult ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbResult,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8526,9 +8561,9 @@ JetCreateIndexA(
_In_ JET_TABLEID tableid,
_In_ JET_PCSTR szIndexName,
_In_ JET_GRBIT grbit,
- _In_reads_bytes_( cbKey ) const char * szKey,
- _In_ unsigned long cbKey,
- _In_ unsigned long lDensity );
+ _In_reads_bytes_( cbKey ) JET_PCSTR szKey,
+ _In_ JET_UINT32 cbKey,
+ _In_ JET_UINT32 lDensity );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8540,13 +8575,13 @@ JetCreateIndexA(
JET_ERR JET_API
JetCreateIndexW(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_ JET_PCWSTR szIndexName,
- _In_ JET_GRBIT grbit,
- _In_reads_bytes_( cbKey ) const WCHAR * szKey,
- _In_ unsigned long cbKey,
- _In_ unsigned long lDensity );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_ JET_PCWSTR szIndexName,
+ _In_ JET_GRBIT grbit,
+ _In_reads_bytes_( cbKey ) JET_PCWSTR szKey,
+ _In_ JET_UINT32 cbKey,
+ _In_ JET_UINT32 lDensity );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8571,7 +8606,7 @@ JetCreateIndex2A(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
_In_reads_( cIndexCreate ) JET_INDEXCREATE_A * pindexcreate,
- _In_ unsigned long cIndexCreate );
+ _In_ JET_UINT32 cIndexCreate );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8586,7 +8621,7 @@ JetCreateIndex2W(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
_In_reads_( cIndexCreate ) JET_INDEXCREATE_W * pindexcreate,
- _In_ unsigned long cIndexCreate );
+ _In_ JET_UINT32 cIndexCreate );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8605,17 +8640,17 @@ JetCreateIndex2W(
JET_ERR JET_API
JetCreateIndex3A(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_reads_( cIndexCreate ) JET_INDEXCREATE2_A *pindexcreate,
- _In_ unsigned long cIndexCreate );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_reads_( cIndexCreate ) JET_INDEXCREATE2_A * pindexcreate,
+ _In_ JET_UINT32 cIndexCreate );
JET_ERR JET_API
JetCreateIndex3W(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_reads_( cIndexCreate ) JET_INDEXCREATE2_W *pindexcreate,
- _In_ unsigned long cIndexCreate );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_reads_( cIndexCreate ) JET_INDEXCREATE2_W * pindexcreate,
+ _In_ JET_UINT32 cIndexCreate );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8635,10 +8670,10 @@ JetCreateIndex3W(
JET_ERR JET_API
JetCreateIndex4A(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_reads_( cIndexCreate ) JET_INDEXCREATE3_A *pindexcreate,
- _In_ unsigned long cIndexCreate );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_reads_( cIndexCreate ) JET_INDEXCREATE3_A * pindexcreate,
+ _In_ JET_UINT32 cIndexCreate );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8648,10 +8683,10 @@ JetCreateIndex4A(
JET_ERR JET_API
JetCreateIndex4W(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_reads_( cIndexCreate ) JET_INDEXCREATE3_W *pindexcreate,
- _In_ unsigned long cIndexCreate );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_reads_( cIndexCreate ) JET_INDEXCREATE3_W * pindexcreate,
+ _In_ JET_UINT32 cIndexCreate );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8724,7 +8759,7 @@ JetBeginTransaction2(
JET_ERR JET_API
JetBeginTransaction3(
_In_ JET_SESID sesid,
- _In_ __int64 trxid,
+ _In_ JET_INT64 trxid,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
@@ -8739,10 +8774,10 @@ JetBeginTransaction3(
JET_ERR JET_API
JetPrepareToCommitTransaction(
- _In_ JET_SESID sesid,
- _In_reads_bytes_( cbData ) const void * pvData,
- _In_ unsigned long cbData,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_reads_bytes_( cbData ) JET_PCVOID pvData,
+ _In_ JET_UINT32 cbData,
+ _In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -8762,7 +8797,7 @@ JET_ERR JET_API
JetCommitTransaction2(
_In_ JET_SESID sesid,
_In_ JET_GRBIT grbit,
- _In_ unsigned long cmsecDurableCommit,
+ _In_ JET_UINT32 cmsecDurableCommit,
_Out_opt_ JET_COMMIT_ID * pCommitId );
#endif // JET_VERSION >= 0x0602
@@ -8782,11 +8817,11 @@ JetRollback(
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT)
JET_ERR JET_API JetGetDatabaseInfoA(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8798,11 +8833,11 @@ JET_ERR JET_API JetGetDatabaseInfoA(
JET_ERR JET_API
JetGetDatabaseInfoW(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8824,10 +8859,10 @@ JetGetDatabaseInfoW(
JET_ERR JET_API
JetGetDatabaseFileInfoA(
- _In_ JET_PCSTR szDatabaseName,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_PCSTR szDatabaseName,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8839,10 +8874,10 @@ JetGetDatabaseFileInfoA(
JET_ERR JET_API
JetGetDatabaseFileInfoW(
- _In_ JET_PCWSTR szDatabaseName,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_PCWSTR szDatabaseName,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -8862,17 +8897,17 @@ JetGetDatabaseFileInfoW(
JET_ERR JET_API
JetGetLogFileInfoA(
- _In_ JET_PCSTR szLog,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ const unsigned long cbMax,
- _In_ const unsigned long InfoLevel );
+ _In_ JET_PCSTR szLog,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ const JET_UINT32 cbMax,
+ _In_ const JET_UINT32 InfoLevel );
JET_ERR JET_API
JetGetLogFileInfoW(
- _In_ JET_PCWSTR szLog,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ const unsigned long cbMax,
- _In_ const unsigned long InfoLevel );
+ _In_ JET_PCWSTR szLog,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ const JET_UINT32 cbMax,
+ _In_ const JET_UINT32 InfoLevel );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -8897,7 +8932,7 @@ JetOpenDatabaseA(
_In_ JET_SESID sesid,
_In_ JET_PCSTR szFilename,
_In_opt_ JET_PCSTR szConnect,
- _Out_ JET_DBID* pdbid,
+ _Out_ JET_DBID * pdbid,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
@@ -8913,7 +8948,7 @@ JetOpenDatabaseW(
_In_ JET_SESID sesid,
_In_ JET_PCWSTR szFilename,
_In_opt_ JET_PCWSTR szConnect,
- _Out_ JET_DBID* pdbid,
+ _Out_ JET_DBID * pdbid,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
@@ -8950,8 +8985,8 @@ JetOpenTableA(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
_In_ JET_PCSTR szTableName,
- _In_reads_bytes_opt_( cbParameters ) const void * pvParameters,
- _In_ unsigned long cbParameters,
+ _In_reads_bytes_opt_( cbParameters ) JET_PCVOID pvParameters,
+ _In_ JET_UINT32 cbParameters,
_In_ JET_GRBIT grbit,
_Out_ JET_TABLEID * ptableid );
@@ -8968,8 +9003,8 @@ JetOpenTableW(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
_In_ JET_PCWSTR szTableName,
- _In_reads_bytes_opt_( cbParameters ) const void * pvParameters,
- _In_ unsigned long cbParameters,
+ _In_reads_bytes_opt_( cbParameters ) JET_PCVOID pvParameters,
+ _In_ JET_UINT32 cbParameters,
_In_ JET_GRBIT grbit,
_Out_ JET_TABLEID * ptableid );
@@ -9027,11 +9062,11 @@ JetDelete(
JET_ERR JET_API
JetUpdate(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_writes_bytes_to_opt_( cbBookmark, *pcbActual ) void * pvBookmark,
- _In_ unsigned long cbBookmark,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_writes_bytes_to_opt_( cbBookmark, *pcbActual ) JET_PVOID pvBookmark,
+ _In_ JET_UINT32 cbBookmark,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9043,12 +9078,12 @@ JetUpdate(
JET_ERR JET_API
JetUpdate2(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_writes_bytes_to_opt_( cbBookmark, *pcbActual ) void * pvBookmark,
- _In_ unsigned long cbBookmark,
- _Out_opt_ unsigned long * pcbActual,
- _In_ const JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_writes_bytes_to_opt_( cbBookmark, *pcbActual ) JET_PVOID pvBookmark,
+ _In_ JET_UINT32 cbBookmark,
+ _Out_opt_ JET_UINT32 * pcbActual,
+ _In_ const JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9060,33 +9095,33 @@ JetUpdate2(
JET_ERR JET_API
JetEscrowUpdate(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_ JET_COLUMNID columnid,
- _In_reads_bytes_( cbMax ) void * pv,
- _In_ unsigned long cbMax,
- _Out_writes_bytes_to_opt_( cbOldMax, *pcbOldActual ) void * pvOld,
- _In_ unsigned long cbOldMax,
- _Out_opt_ unsigned long * pcbOldActual,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_ JET_COLUMNID columnid,
+ _In_reads_bytes_( cbMax ) JET_PVOID pv,
+ _In_ JET_UINT32 cbMax,
+ _Out_writes_bytes_to_opt_( cbOldMax, *pcbOldActual ) JET_PVOID pvOld,
+ _In_ JET_UINT32 cbOldMax,
+ _Out_opt_ JET_UINT32 * pcbOldActual,
+ _In_ JET_GRBIT grbit );
JET_ERR JET_API
JetRetrieveColumn(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_ JET_COLUMNID columnid,
- _Out_writes_bytes_to_opt_( cbData, min( cbData, *pcbActual ) ) void * pvData,
- _In_ unsigned long cbData,
- _Out_opt_ unsigned long * pcbActual,
- _In_ JET_GRBIT grbit,
- _Inout_opt_ JET_RETINFO * pretinfo );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_ JET_COLUMNID columnid,
+ _Out_writes_bytes_to_opt_( cbData, min( cbData, *pcbActual ) ) JET_PVOID pvData,
+ _In_ JET_UINT32 cbData,
+ _Out_opt_ JET_UINT32 * pcbActual,
+ _In_ JET_GRBIT grbit,
+ _Inout_opt_ JET_RETINFO * pretinfo );
JET_ERR JET_API
JetRetrieveColumns(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Inout_updates_opt_( cretrievecolumn ) JET_RETRIEVECOLUMN * pretrievecolumn,
- _In_ unsigned long cretrievecolumn );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Inout_updates_opt_( cretrievecolumn ) JET_RETRIEVECOLUMN * pretrievecolumn,
+ _In_ JET_UINT32 cretrievecolumn );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9098,16 +9133,16 @@ JetRetrieveColumns(
JET_ERR JET_API
JetEnumerateColumns(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_ unsigned long cEnumColumnId,
- _In_reads_opt_( cEnumColumnId ) JET_ENUMCOLUMNID * rgEnumColumnId,
- _Out_ unsigned long * pcEnumColumn,
- _Outptr_result_buffer_( *pcEnumColumn ) JET_ENUMCOLUMN ** prgEnumColumn,
- _In_ JET_PFNREALLOC pfnRealloc,
- _In_opt_ void * pvReallocContext,
- _In_ unsigned long cbDataMost,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_ JET_UINT32 cEnumColumnId,
+ _In_reads_opt_( cEnumColumnId ) JET_ENUMCOLUMNID * rgEnumColumnId,
+ _Out_ JET_UINT32 * pcEnumColumn,
+ _Outptr_result_buffer_( *pcEnumColumn ) JET_ENUMCOLUMN ** prgEnumColumn,
+ _In_ JET_PFNREALLOC pfnRealloc,
+ _In_opt_ JET_PVOID pvReallocContext,
+ _In_ JET_UINT32 cbDataMost,
+ _In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9121,13 +9156,13 @@ JetEnumerateColumns(
JET_ERR JET_API
JetRetrieveTaggedColumnList(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_ unsigned long * pcColumns,
- _Out_writes_bytes_to_opt_( cbData, *pcColumns * sizeof( JET_RETRIEVEMULTIVALUECOUNT ) ) void * pvData,
- _In_ unsigned long cbData,
- _In_ JET_COLUMNID columnidStart,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_ JET_UINT32 * pcColumns,
+ _Out_writes_bytes_to_opt_( cbData, *pcColumns * sizeof( JET_RETRIEVEMULTIVALUECOUNT ) ) JET_PVOID pvData,
+ _In_ JET_UINT32 cbData,
+ _In_ JET_COLUMNID columnidStart,
+ _In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -9175,7 +9210,7 @@ JET_ERR JET_API
JetGetRecordSize3(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
- _Inout_ JET_RECSIZE3 * precsize,
+ _Inout_ JET_RECSIZE3 * precsize,
_In_ const JET_GRBIT grbit );
#endif // JET_VERSION >= 0x0A01
@@ -9187,33 +9222,33 @@ JetGetRecordSize3(
JET_ERR JET_API
JetSetColumn(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_ JET_COLUMNID columnid,
- _In_reads_bytes_opt_( cbData ) const void * pvData,
- _In_ unsigned long cbData,
- _In_ JET_GRBIT grbit,
- _In_opt_ JET_SETINFO * psetinfo );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_ JET_COLUMNID columnid,
+ _In_reads_bytes_opt_( cbData ) JET_PCVOID pvData,
+ _In_ JET_UINT32 cbData,
+ _In_ JET_GRBIT grbit,
+ _In_opt_ JET_SETINFO * psetinfo );
JET_ERR JET_API
JetSetColumns(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
_In_reads_opt_( csetcolumn ) JET_SETCOLUMN * psetcolumn,
- _In_ unsigned long csetcolumn );
+ _In_ JET_UINT32 csetcolumn );
JET_ERR JET_API
JetPrepareUpdate(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
- _In_ unsigned long prep );
+ _In_ JET_UINT32 prep );
JET_ERR JET_API
JetGetRecordPosition(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_writes_bytes_( cbRecpos ) JET_RECPOS * precpos,
- _In_ unsigned long cbRecpos );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_writes_bytes_( cbRecpos ) JET_RECPOS * precpos,
+ _In_ JET_UINT32 cbRecpos );
JET_ERR JET_API
JetGotoPosition(
@@ -9229,18 +9264,18 @@ JetGotoPosition(
JET_ERR JET_API
JetGetCursorInfo(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
JET_ERR JET_API
JetDupCursor(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_ JET_TABLEID * ptableid,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_ JET_TABLEID * ptableid,
+ _In_ JET_GRBIT grbit );
#if ( JET_VERSION < 0x0600 )
#define JetGetCurrentIndexA JetGetCurrentIndex
@@ -9251,7 +9286,7 @@ JetGetCurrentIndexA(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
_Out_writes_bytes_( cbIndexName ) JET_PSTR szIndexName,
- _In_ unsigned long cbIndexName );
+ _In_ JET_UINT32 cbIndexName );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9266,7 +9301,7 @@ JetGetCurrentIndexW(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
_Out_writes_bytes_( cbIndexName ) JET_PWSTR szIndexName,
- _In_ unsigned long cbIndexName );
+ _In_ JET_UINT32 cbIndexName );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9369,7 +9404,7 @@ JetSetCurrentIndex3A(
_In_ JET_TABLEID tableid,
_In_opt_ JET_PCSTR szIndexName,
_In_ JET_GRBIT grbit,
- _In_ unsigned long itagSequence );
+ _In_ JET_UINT32 itagSequence );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9385,7 +9420,7 @@ JetSetCurrentIndex3W(
_In_ JET_TABLEID tableid,
_In_opt_ JET_PCWSTR szIndexName,
_In_ JET_GRBIT grbit,
- _In_ unsigned long itagSequence );
+ _In_ JET_UINT32 itagSequence );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9412,7 +9447,7 @@ JetSetCurrentIndex4A(
_In_opt_ JET_PCSTR szIndexName,
_In_opt_ JET_INDEXID * pindexid,
_In_ JET_GRBIT grbit,
- _In_ unsigned long itagSequence );
+ _In_ JET_UINT32 itagSequence );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9429,7 +9464,7 @@ JetSetCurrentIndex4W(
_In_opt_ JET_PCWSTR szIndexName,
_In_opt_ JET_INDEXID * pindexid,
_In_ JET_GRBIT grbit,
- _In_ unsigned long itagSequence );
+ _In_ JET_UINT32 itagSequence );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9449,17 +9484,17 @@ JET_ERR JET_API
JetMove(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
- _In_ long cRow,
+ _In_ JET_INT32 cRow,
_In_ JET_GRBIT grbit );
#if ( JET_VERSION >= 0x0602 )
JET_ERR JET_API
JetSetCursorFilter(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_reads_( cColumnFilters ) JET_INDEX_COLUMN *rgColumnFilters,
- _In_ unsigned long cColumnFilters,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_reads_( cColumnFilters ) JET_INDEX_COLUMN * rgColumnFilters,
+ _In_ JET_UINT32 cColumnFilters,
+ _In_ JET_GRBIT grbit );
#endif // JET_VERSION >= 0x0602
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
@@ -9482,11 +9517,11 @@ JetGetLock(
JET_ERR JET_API
JetMakeKey(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_reads_bytes_opt_( cbData ) const void * pvData,
- _In_ unsigned long cbData,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_reads_bytes_opt_( cbData ) JET_PCVOID pvData,
+ _In_ JET_UINT32 cbData,
+ _In_ JET_GRBIT grbit );
JET_ERR JET_API
JetSeek(
@@ -9502,14 +9537,15 @@ JetSeek(
#pragma region Application Family or Esent Package
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT)
+// FOOBY
JET_ERR JET_API
JetPrereadKeys(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
- _In_reads_(ckeys) const void ** rgpvKeys,
- _In_reads_(ckeys) const unsigned long * rgcbKeys,
- _In_ long ckeys,
- _Out_opt_ long * pckeysPreread,
+ _In_reads_(ckeys) JET_PCVOID * rgpvKeys,
+ _In_reads_(ckeys) const JET_UINT32 * rgcbKeys,
+ _In_ JET_INT32 ckeys,
+ _Out_opt_ JET_INT32 * pckeysPreread,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
@@ -9527,21 +9563,21 @@ JetPrereadIndexRanges(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
_In_reads_(cIndexRanges) const JET_INDEX_RANGE * const rgIndexRanges,
- _In_ const unsigned long cIndexRanges,
- _Out_opt_ unsigned long * const pcRangesPreread,
+ _In_ const JET_UINT32 cIndexRanges,
+ _Out_opt_ JET_UINT32 * const pcRangesPreread,
_In_reads_(ccolumnidPreread) const JET_COLUMNID * const rgcolumnidPreread,
- _In_ const unsigned long ccolumnidPreread,
+ _In_ const JET_UINT32 ccolumnidPreread,
_In_ JET_GRBIT grbit ); // JET_bitPrereadForward, JET_bitPrereadBackward
#endif // JET_VERSION >= 0x0602
JET_ERR JET_API
JetGetBookmark(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) void * pvBookmark,
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PVOID pvBookmark,
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9553,15 +9589,15 @@ JetGetBookmark(
JET_ERR JET_API
JetGetSecondaryIndexBookmark(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_writes_bytes_to_opt_( cbSecondaryKeyMax, *pcbSecondaryKeyActual ) void * pvSecondaryKey,
- _In_ unsigned long cbSecondaryKeyMax,
- _Out_opt_ unsigned long * pcbSecondaryKeyActual,
- _Out_writes_bytes_to_opt_( cbPrimaryBookmarkMax, *pcbPrimaryBookmarkActual ) void * pvPrimaryBookmark,
- _In_ unsigned long cbPrimaryBookmarkMax,
- _Out_opt_ unsigned long * pcbPrimaryBookmarkActual,
- _In_ const JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_writes_bytes_to_opt_( cbSecondaryKeyMax, *pcbSecondaryKeyActual ) JET_PVOID pvSecondaryKey,
+ _In_ JET_UINT32 cbSecondaryKeyMax,
+ _Out_opt_ JET_UINT32 * pcbSecondaryKeyActual,
+ _Out_writes_bytes_to_opt_( cbPrimaryBookmarkMax, *pcbPrimaryBookmarkActual ) JET_PVOID pvPrimaryBookmark,
+ _In_ JET_UINT32 cbPrimaryBookmarkMax,
+ _Out_opt_ JET_UINT32 * pcbPrimaryBookmarkActual,
+ _In_ const JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9625,8 +9661,8 @@ JetDefragmentA(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
_In_opt_ JET_PCSTR szTableName,
- _Inout_opt_ unsigned long * pcPasses,
- _Inout_opt_ unsigned long * pcSeconds,
+ _Inout_opt_ JET_UINT32 * pcPasses,
+ _Inout_opt_ JET_UINT32 * pcSeconds,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
@@ -9642,8 +9678,8 @@ JetDefragmentW(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
_In_opt_ JET_PCWSTR szTableName,
- _Inout_opt_ unsigned long * pcPasses,
- _Inout_opt_ unsigned long * pcSeconds,
+ _Inout_opt_ JET_UINT32 * pcPasses,
+ _Inout_opt_ JET_UINT32 * pcSeconds,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
@@ -9670,8 +9706,8 @@ JetDefragment2A(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
_In_opt_ JET_PCSTR szTableName,
- _Inout_opt_ unsigned long * pcPasses,
- _Inout_opt_ unsigned long * pcSeconds,
+ _Inout_opt_ JET_UINT32 * pcPasses,
+ _Inout_opt_ JET_UINT32 * pcSeconds,
_In_ JET_CALLBACK callback,
_In_ JET_GRBIT grbit );
@@ -9688,8 +9724,8 @@ JetDefragment2W(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
_In_opt_ JET_PCWSTR szTableName,
- _Inout_opt_ unsigned long * pcPasses,
- _Inout_opt_ unsigned long * pcSeconds,
+ _Inout_opt_ JET_UINT32 * pcPasses,
+ _Inout_opt_ JET_UINT32 * pcSeconds,
_In_ JET_CALLBACK callback,
_In_ JET_GRBIT grbit );
@@ -9716,10 +9752,10 @@ JetDefragment3A(
_In_ JET_SESID sesid,
_In_ JET_PCSTR szDatabaseName,
_In_opt_ JET_PCSTR szTableName,
- _Inout_opt_ unsigned long * pcPasses,
- _Inout_opt_ unsigned long * pcSeconds,
+ _Inout_opt_ JET_UINT32 * pcPasses,
+ _Inout_opt_ JET_UINT32 * pcSeconds,
_In_ JET_CALLBACK callback,
- _In_ void * pvContext,
+ _In_ JET_PVOID pvContext,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
@@ -9735,10 +9771,10 @@ JetDefragment3W(
_In_ JET_SESID sesid,
_In_ JET_PCWSTR szDatabaseName,
_In_opt_ JET_PCWSTR szTableName,
- _Inout_opt_ unsigned long * pcPasses,
- _Inout_opt_ unsigned long * pcSeconds,
+ _Inout_opt_ JET_UINT32 * pcPasses,
+ _Inout_opt_ JET_UINT32 * pcSeconds,
_In_ JET_CALLBACK callback,
- _In_ void * pvContext,
+ _In_ JET_PVOID pvContext,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
@@ -9762,12 +9798,12 @@ JetDefragment3W(
JET_ERR JET_API
JetDatabaseScan(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _Inout_opt_ unsigned long * pcSecondsMax,
- _In_ unsigned long cmsecSleep,
- _In_ JET_CALLBACK pfnCallback,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _Inout_opt_ JET_UINT32 * pcSecondsMax,
+ _In_ JET_UINT32 cmsecSleep,
+ _In_ JET_CALLBACK pfnCallback,
+ _In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -9783,11 +9819,11 @@ JetDatabaseScan(
JET_ERR JET_API
JetConvertDDLA(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_OPDDLCONV convtyp,
- _Out_writes_bytes_( cbData ) void * pvData,
- _In_ unsigned long cbData );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_OPDDLCONV convtyp,
+ _Out_writes_bytes_( cbData ) JET_PVOID pvData,
+ _In_ JET_UINT32 cbData );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -9799,11 +9835,11 @@ JetConvertDDLA(
JET_ERR JET_API
JetConvertDDLW(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ JET_OPDDLCONV convtyp,
- _Out_writes_bytes_( cbData ) void * pvData,
- _In_ unsigned long cbData );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_OPDDLCONV convtyp,
+ _Out_writes_bytes_( cbData ) JET_PVOID pvData,
+ _In_ JET_UINT32 cbData );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -9867,14 +9903,14 @@ JET_ERR JET_API
JetSetMaxDatabaseSize(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
- _In_ unsigned long cpg,
+ _In_ JET_UINT32 cpg,
_In_ JET_GRBIT grbit );
JET_ERR JET_API
JetGetMaxDatabaseSize(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
- _Out_ unsigned long * pcpg,
+ _Out_ JET_UINT32 * pcpg,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
@@ -9894,8 +9930,8 @@ JET_ERR JET_API
JetSetDatabaseSizeA(
_In_ JET_SESID sesid,
_In_ JET_PCSTR szDatabaseName,
- _In_ unsigned long cpg,
- _Out_ unsigned long * pcpgReal );
+ _In_ JET_UINT32 cpg,
+ _Out_ JET_UINT32 * pcpgReal );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9909,8 +9945,8 @@ JET_ERR JET_API
JetSetDatabaseSizeW(
_In_ JET_SESID sesid,
_In_ JET_PCWSTR szDatabaseName,
- _In_ unsigned long cpg,
- _Out_ unsigned long * pcpgReal );
+ _In_ JET_UINT32 cpg,
+ _Out_ JET_UINT32 * pcpgReal );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9929,8 +9965,8 @@ JET_ERR JET_API
JetGrowDatabase(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
- _In_ unsigned long cpg,
- _In_ unsigned long * pcpgReal );
+ _In_ JET_UINT32 cpg,
+ _In_ JET_UINT32 * pcpgReal );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -9943,8 +9979,8 @@ JET_ERR JET_API
JetResizeDatabase(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
- _In_ unsigned long cpgTarget,
- _Out_ unsigned long * pcpgActual,
+ _In_ JET_UINT32 cpgTarget,
+ _Out_ JET_UINT32 * pcpgActual,
_In_ const JET_GRBIT grbit );
#endif // JET_VERSION >= 0x0602
@@ -9966,10 +10002,10 @@ JetResetSessionContext(
#if ( JET_VERSION < 0x0600 )
#define JetDBUtilitiesA JetDBUtilities
#endif
-JET_ERR JET_API JetDBUtilitiesA( JET_DBUTIL_A *pdbutil );
+JET_ERR JET_API JetDBUtilitiesA( JET_DBUTIL_A * pdbutil );
#if ( JET_VERSION >= 0x0600 )
-JET_ERR JET_API JetDBUtilitiesW( JET_DBUTIL_W *pdbutil );
+JET_ERR JET_API JetDBUtilitiesW( JET_DBUTIL_W * pdbutil );
#ifdef JET_UNICODE
#define JetDBUtilities JetDBUtilitiesW
#else
@@ -9985,10 +10021,10 @@ JET_ERR JET_API JetDBUtilitiesW( JET_DBUTIL_W *pdbutil );
JET_ERR JET_API
JetGotoBookmark(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_reads_bytes_( cbBookmark ) void * pvBookmark,
- _In_ unsigned long cbBookmark );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_reads_bytes_( cbBookmark ) JET_PVOID pvBookmark,
+ _In_ JET_UINT32 cbBookmark );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10000,13 +10036,13 @@ JetGotoBookmark(
JET_ERR JET_API
JetGotoSecondaryIndexBookmark(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _In_reads_bytes_( cbSecondaryKey ) void * pvSecondaryKey,
- _In_ unsigned long cbSecondaryKey,
- _In_reads_bytes_opt_( cbPrimaryBookmark ) void * pvPrimaryBookmark,
- _In_ unsigned long cbPrimaryBookmark,
- _In_ const JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _In_reads_bytes_( cbSecondaryKey ) JET_PVOID pvSecondaryKey,
+ _In_ JET_UINT32 cbSecondaryKey,
+ _In_reads_bytes_opt_( cbPrimaryBookmark ) JET_PVOID pvPrimaryBookmark,
+ _In_ JET_UINT32 cbPrimaryBookmark,
+ _In_ const JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
@@ -10021,7 +10057,7 @@ JET_ERR JET_API
JetIntersectIndexes(
_In_ JET_SESID sesid,
_In_reads_( cindexrange ) JET_INDEXRANGE * rgindexrange,
- _In_ unsigned long cindexrange,
+ _In_ JET_UINT32 cindexrange,
_Inout_ JET_RECORDLIST * precordlist,
_In_ JET_GRBIT grbit );
@@ -10039,8 +10075,8 @@ JetComputeStats(
JET_ERR JET_API
JetOpenTempTable(
_In_ JET_SESID sesid,
- _In_reads_( ccolumn ) const JET_COLUMNDEF * prgcolumndef,
- _In_ unsigned long ccolumn,
+ _In_reads_( ccolumn ) const JET_COLUMNDEF * prgcolumndef,
+ _In_ JET_UINT32 ccolumn,
_In_ JET_GRBIT grbit,
_Out_ JET_TABLEID * ptableid,
_Out_writes_( ccolumn ) JET_COLUMNID * prgcolumnid );
@@ -10048,9 +10084,9 @@ JetOpenTempTable(
JET_ERR JET_API
JetOpenTempTable2(
_In_ JET_SESID sesid,
- _In_reads_( ccolumn ) const JET_COLUMNDEF * prgcolumndef,
- _In_ unsigned long ccolumn,
- _In_ unsigned long lcid,
+ _In_reads_( ccolumn ) const JET_COLUMNDEF * prgcolumndef,
+ _In_ JET_UINT32 ccolumn,
+ _In_ JET_UINT32 lcid,
_In_ JET_GRBIT grbit,
_Out_ JET_TABLEID * ptableid,
_Out_writes_( ccolumn ) JET_COLUMNID * prgcolumnid );
@@ -10064,8 +10100,8 @@ JetOpenTempTable2(
JET_ERR JET_API
JetOpenTempTable3(
_In_ JET_SESID sesid,
- _In_reads_( ccolumn ) const JET_COLUMNDEF * prgcolumndef,
- _In_ unsigned long ccolumn,
+ _In_reads_( ccolumn ) const JET_COLUMNDEF * prgcolumndef,
+ _In_ JET_UINT32 ccolumn,
_In_opt_ JET_UNICODEINDEX * pidxunicode,
_In_ JET_GRBIT grbit,
_Out_ JET_TABLEID * ptableid,
@@ -10314,8 +10350,8 @@ JET_ERR JET_API
JetIndexRecordCount(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
- _Out_ unsigned long * pcrec,
- _In_ unsigned long crecMax );
+ _Out_ JET_UINT32 * pcrec,
+ _In_ JET_UINT32 crecMax );
// end_PubEsent
#if ( JET_VERSION >= 0x0A01 )
@@ -10324,20 +10360,20 @@ JET_ERR JET_API
JetIndexRecordCount2(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
- _Out_ unsigned __int64 * pcrec,
- _In_ unsigned __int64 crecMax );
+ _Out_ JET_UINT64 * pcrec,
+ _In_ JET_UINT64 crecMax );
#endif // JET_VERSION >= 0x0A01
// begin_PubEsent
JET_ERR JET_API
JetRetrieveKey(
- _In_ JET_SESID sesid,
- _In_ JET_TABLEID tableid,
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) void * pvKey,
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_TABLEID tableid,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PVOID pvKey,
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual,
+ _In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10373,8 +10409,8 @@ JET_ERR JET_API JetBeginExternalBackupInstance(
JET_ERR JET_API JetBeginSurrogateBackup(
_In_ JET_INSTANCE instance,
- _In_ unsigned long lgenFirst,
- _In_ unsigned long lgenLast,
+ _In_ JET_UINT32 lgenFirst,
+ _In_ JET_UINT32 lgenLast,
_In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
@@ -10393,12 +10429,12 @@ JET_ERR JET_API JetBeginSurrogateBackup(
JET_ERR JET_API
JetGetAttachInfoA(
#if ( JET_VERSION < 0x0600 )
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) void * pv,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PVOID pv,
#else
_Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzDatabases,
#endif
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10411,8 +10447,8 @@ JetGetAttachInfoA(
JET_ERR JET_API
JetGetAttachInfoW(
_Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PWSTR wszzDatabases,
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10435,14 +10471,14 @@ JetGetAttachInfoW(
JET_ERR JET_API
JetGetAttachInfoInstanceA(
- _In_ JET_INSTANCE instance,
+ _In_ JET_INSTANCE instance,
#if ( JET_VERSION < 0x0600 )
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) void * pv,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PVOID pv,
#else
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzDatabases,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzDatabases,
#endif
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10456,8 +10492,8 @@ JET_ERR JET_API
JetGetAttachInfoInstanceW(
_In_ JET_INSTANCE instance,
_Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PWSTR szzDatabases,
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10483,8 +10519,8 @@ JET_ERR JET_API
JetOpenFileA(
_In_ JET_PCSTR szFileName,
_Out_ JET_HANDLE * phfFile,
- _Out_ unsigned long * pulFileSizeLow,
- _Out_ unsigned long * pulFileSizeHigh );
+ _Out_ JET_UINT32 * pulFileSizeLow,
+ _Out_ JET_UINT32 * pulFileSizeHigh );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10498,8 +10534,8 @@ JET_ERR JET_API
JetOpenFileW(
_In_ JET_PCWSTR szFileName,
_Out_ JET_HANDLE * phfFile,
- _Out_ unsigned long * pulFileSizeLow,
- _Out_ unsigned long * pulFileSizeHigh );
+ _Out_ JET_UINT32 * pulFileSizeLow,
+ _Out_ JET_UINT32 * pulFileSizeHigh );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10525,8 +10561,8 @@ JetOpenFileInstanceA(
_In_ JET_INSTANCE instance,
_In_ JET_PCSTR szFileName,
_Out_ JET_HANDLE * phfFile,
- _Out_ unsigned long * pulFileSizeLow,
- _Out_ unsigned long * pulFileSizeHigh );
+ _Out_ JET_UINT32 * pulFileSizeLow,
+ _Out_ JET_UINT32 * pulFileSizeHigh );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10541,8 +10577,8 @@ JetOpenFileInstanceW(
_In_ JET_INSTANCE instance,
_In_ JET_PCWSTR szFileName,
_Out_ JET_HANDLE * phfFile,
- _Out_ unsigned long * pulFileSizeLow,
- _Out_ unsigned long * pulFileSizeHigh );
+ _Out_ JET_UINT32 * pulFileSizeLow,
+ _Out_ JET_UINT32 * pulFileSizeHigh );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10569,11 +10605,11 @@ JetOpenFileSectionInstanceA(
_In_ JET_INSTANCE instance,
_In_ JET_PSTR szFile,
_Out_ JET_HANDLE * phFile,
- _In_ long iSection,
- _In_ long cSections,
- _In_ unsigned __int64 ibRead,
- _Out_ unsigned long * pulSectionSizeLow,
- _Out_ long * plSectionSizeHigh );
+ _In_ JET_INT32 iSection,
+ _In_ JET_INT32 cSections,
+ _In_ JET_UINT64 ibRead,
+ _Out_ JET_UINT32 * pulSectionSizeLow,
+ _Out_ JET_INT32 * plSectionSizeHigh );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -10588,11 +10624,11 @@ JetOpenFileSectionInstanceW(
_In_ JET_INSTANCE instance,
_In_ JET_PWSTR szFile,
_Out_ JET_HANDLE * phFile,
- _In_ long iSection,
- _In_ long cSections,
- _In_ unsigned __int64 ibRead,
- _Out_ unsigned long * pulSectionSizeLow,
- _Out_ long * plSectionSizeHigh );
+ _In_ JET_INT32 iSection,
+ _In_ JET_INT32 cSections,
+ _In_ JET_UINT64 ibRead,
+ _Out_ JET_UINT32 * pulSectionSizeLow,
+ _Out_ JET_INT32 * plSectionSizeHigh );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -10612,10 +10648,10 @@ JetOpenFileSectionInstanceW(
JET_ERR JET_API
JetReadFile(
- _In_ JET_HANDLE hfFile,
- _Out_writes_bytes_to_( cb, *pcbActual ) void * pv,
- _In_ unsigned long cb,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_HANDLE hfFile,
+ _Out_writes_bytes_to_( cb, *pcbActual ) JET_PVOID pv,
+ _In_ JET_UINT32 cb,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10627,11 +10663,11 @@ JetReadFile(
JET_ERR JET_API
JetReadFileInstance(
- _In_ JET_INSTANCE instance,
- _In_ JET_HANDLE hfFile,
- _Out_writes_bytes_to_( cb, *pcbActual ) void * pv,
- _In_ unsigned long cb,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_INSTANCE instance,
+ _In_ JET_HANDLE hfFile,
+ _Out_writes_bytes_to_( cb, *pcbActual ) JET_PVOID pv,
+ _In_ JET_UINT32 cb,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10673,12 +10709,12 @@ JetCloseFileInstance(
JET_ERR JET_API
JetGetLogInfoA(
#if ( JET_VERSION < 0x0600 )
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) void * pv,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PVOID pv,
#else
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzLogs,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzLogs,
#endif
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10691,8 +10727,8 @@ JetGetLogInfoA(
JET_ERR JET_API
JetGetLogInfoW(
_Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PWSTR szzLogs,
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10715,14 +10751,14 @@ JetGetLogInfoW(
JET_ERR JET_API
JetGetLogInfoInstanceA(
- _In_ JET_INSTANCE instance,
+ _In_ JET_INSTANCE instance,
#if ( JET_VERSION < 0x0600 )
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) void * pv,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PVOID pv,
#else
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzLogs,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzLogs,
#endif
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10734,10 +10770,10 @@ JetGetLogInfoInstanceA(
JET_ERR JET_API
JetGetLogInfoInstanceW(
- _In_ JET_INSTANCE instance,
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PWSTR wszzLogs,
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_INSTANCE instance,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PWSTR wszzLogs,
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10755,18 +10791,18 @@ JetGetLogInfoInstanceW(
#define JET_BASE_NAME_LENGTH 3
typedef struct
{
- unsigned long cbSize;
- unsigned long ulGenLow;
- unsigned long ulGenHigh;
- char szBaseName[ JET_BASE_NAME_LENGTH + 1 ];
+ JET_UINT32 cbSize;
+ JET_UINT32 ulGenLow;
+ JET_UINT32 ulGenHigh;
+ JET_CHAR szBaseName[ JET_BASE_NAME_LENGTH + 1 ];
} JET_LOGINFO_A;
typedef struct
{
- unsigned long cbSize;
- unsigned long ulGenLow;
- unsigned long ulGenHigh;
- WCHAR szBaseName[ JET_BASE_NAME_LENGTH + 1 ];
+ JET_UINT32 cbSize;
+ JET_UINT32 ulGenLow;
+ JET_UINT32 ulGenHigh;
+ JET_WCHAR szBaseName[ JET_BASE_NAME_LENGTH + 1 ];
} JET_LOGINFO_W;
#ifdef JET_UNICODE
@@ -10784,15 +10820,15 @@ typedef struct
JET_ERR JET_API
JetGetLogInfoInstance2A(
- _In_ JET_INSTANCE instance,
+ _In_ JET_INSTANCE instance,
#if ( JET_VERSION < 0x0600 )
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) void * pv,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PVOID pv,
#else
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzLogs,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzLogs,
#endif
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual,
- _Inout_opt_ JET_LOGINFO_A * pLogInfo );
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual,
+ _Inout_opt_ JET_LOGINFO_A * pLogInfo );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10804,11 +10840,11 @@ JetGetLogInfoInstance2A(
JET_ERR JET_API
JetGetLogInfoInstance2W(
- _In_ JET_INSTANCE instance,
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PWSTR wszzLogs,
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual,
- _Inout_opt_ JET_LOGINFO_W * pLogInfo );
+ _In_ JET_INSTANCE instance,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PWSTR wszzLogs,
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual,
+ _Inout_opt_ JET_LOGINFO_W * pLogInfo );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10830,14 +10866,14 @@ JetGetLogInfoInstance2W(
JET_ERR JET_API
JetGetTruncateLogInfoInstanceA(
- _In_ JET_INSTANCE instance,
+ _In_ JET_INSTANCE instance,
#if ( JET_VERSION < 0x0600 )
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) void * pv,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PVOID pv,
#else
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzLogs,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PSTR szzLogs,
#endif
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10849,10 +10885,10 @@ JetGetTruncateLogInfoInstanceA(
JET_ERR JET_API
JetGetTruncateLogInfoInstanceW(
- _In_ JET_INSTANCE instance,
- _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PWSTR wszzLogs,
- _In_ unsigned long cbMax,
- _Out_opt_ unsigned long * pcbActual );
+ _In_ JET_INSTANCE instance,
+ _Out_writes_bytes_to_opt_( cbMax, *pcbActual ) JET_PWSTR wszzLogs,
+ _In_ JET_UINT32 cbMax,
+ _Out_opt_ JET_UINT32 * pcbActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10870,7 +10906,7 @@ JetGetTruncateLogInfoInstanceW(
#pragma region Desktop Family or Esent Package
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT)
-JET_ERR JET_API JetTruncateLog( void );
+JET_ERR JET_API JetTruncateLog( JET_VOID );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10892,7 +10928,7 @@ JetTruncateLogInstance(
#pragma region Desktop Family or Esent Package
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT)
-JET_ERR JET_API JetEndExternalBackup( void );
+JET_ERR JET_API JetEndExternalBackup( JET_VOID );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -10945,10 +10981,10 @@ JetExternalRestoreA(
_In_ JET_PSTR szCheckpointFilePath,
_In_ JET_PSTR szLogPath,
_In_reads_opt_( crstfilemap ) JET_RSTMAP_A * rgrstmap,
- _In_ long crstfilemap,
+ _In_ JET_INT32 crstfilemap,
_In_ JET_PSTR szBackupLogPath,
- _In_ long genLow,
- _In_ long genHigh,
+ _In_ JET_INT32 genLow,
+ _In_ JET_INT32 genHigh,
_In_ JET_PFNSTATUS pfn );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
@@ -10964,10 +11000,10 @@ JetExternalRestoreW(
_In_ JET_PWSTR szCheckpointFilePath,
_In_ JET_PWSTR szLogPath,
_In_reads_opt_( crstfilemap ) JET_RSTMAP_W * rgrstmap,
- _In_ long crstfilemap,
+ _In_ JET_INT32 crstfilemap,
_In_ JET_PWSTR szBackupLogPath,
- _In_ long genLow,
- _In_ long genHigh,
+ _In_ JET_INT32 genLow,
+ _In_ JET_INT32 genHigh,
_In_ JET_PFNSTATUS pfn );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
@@ -10994,7 +11030,7 @@ JetExternalRestore2A(
_In_ JET_PSTR szCheckpointFilePath,
_In_ JET_PSTR szLogPath,
_In_reads_opt_( crstfilemap ) JET_RSTMAP_A * rgrstmap,
- _In_ long crstfilemap,
+ _In_ JET_INT32 crstfilemap,
_In_ JET_PSTR szBackupLogPath,
_Inout_ JET_LOGINFO_A * pLogInfo,
_In_opt_ JET_PSTR szTargetInstanceName,
@@ -11015,7 +11051,7 @@ JetExternalRestore2W(
_In_ JET_PWSTR szCheckpointFilePath,
_In_ JET_PWSTR szLogPath,
_In_reads_opt_( crstfilemap ) JET_RSTMAP_W * rgrstmap,
- _In_ long crstfilemap,
+ _In_ JET_INT32 crstfilemap,
_In_ JET_PWSTR szBackupLogPath,
_Inout_ JET_LOGINFO_W * pLogInfo,
_In_opt_ JET_PWSTR szTargetInstanceName,
@@ -11093,7 +11129,7 @@ JetRegisterCallback(
_In_ JET_TABLEID tableid,
_In_ JET_CBTYP cbtyp,
_In_ JET_CALLBACK pCallback,
- _In_opt_ void * pvContext,
+ _In_opt_ JET_PVOID pvContext,
_In_ JET_HANDLE * phCallbackId );
JET_ERR JET_API
@@ -11109,23 +11145,23 @@ JetUnregisterCallback(
typedef struct _JET_INSTANCE_INFO_A
{
JET_INSTANCE hInstanceId;
- char * szInstanceName;
+ JET_PSTR szInstanceName;
JET_API_PTR cDatabases;
- char ** szDatabaseFileName;
- char ** szDatabaseDisplayName;
- char ** szDatabaseSLVFileName_Obsolete;
+ JET_PSTR * szDatabaseFileName;
+ JET_PSTR * szDatabaseDisplayName;
+ JET_PSTR * szDatabaseSLVFileName_Obsolete;
} JET_INSTANCE_INFO_A;
typedef struct _JET_INSTANCE_INFO_W
{
JET_INSTANCE hInstanceId;
- WCHAR * szInstanceName;
+ JET_PWSTR szInstanceName;
JET_API_PTR cDatabases;
- WCHAR ** szDatabaseFileName;
- WCHAR ** szDatabaseDisplayName;
- WCHAR ** szDatabaseSLVFileName_Obsolete;
+ JET_PWSTR * szDatabaseFileName;
+ JET_PWSTR * szDatabaseDisplayName;
+ JET_PWSTR * szDatabaseSLVFileName_Obsolete;
} JET_INSTANCE_INFO_W;
#ifdef JET_UNICODE
@@ -11143,8 +11179,8 @@ typedef struct _JET_INSTANCE_INFO_W
JET_ERR JET_API
JetGetInstanceInfoA(
- _Out_ unsigned long * pcInstanceInfo,
- _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_A ** paInstanceInfo );
+ _Out_ JET_UINT32 * pcInstanceInfo,
+ _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_A ** paInstanceInfo );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -11156,8 +11192,8 @@ JetGetInstanceInfoA(
JET_ERR JET_API
JetGetInstanceInfoW(
- _Out_ unsigned long * pcInstanceInfo,
- _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_W ** paInstanceInfo );
+ _Out_ JET_UINT32 * pcInstanceInfo,
+ _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_W ** paInstanceInfo );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -11174,7 +11210,7 @@ JetGetInstanceInfoW(
JET_ERR JET_API
JetFreeBuffer(
- _Pre_notnull_ char * pbBuf );
+ _Pre_notnull_ JET_CHAR * pbBuf );
JET_ERR JET_API
JetSetLS(
@@ -11215,7 +11251,7 @@ JetTracing(
#pragma region Desktop Family or Esent Package
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT)
-typedef JET_API_PTR JET_OSSNAPID; /* Snapshot Session Identifier */
+typedef JET_API_PTR JET_OSSNAPID; // Snapshot Session Identifier
JET_ERR JET_API
JetOSSnapshotPrepare(
@@ -11236,19 +11272,19 @@ JetOSSnapshotPrepareInstance(
JET_ERR JET_API
JetOSSnapshotFreezeA(
- _In_ const JET_OSSNAPID snapId,
- _Out_ unsigned long * pcInstanceInfo,
- _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_A ** paInstanceInfo,
- _In_ const JET_GRBIT grbit );
+ _In_ const JET_OSSNAPID snapId,
+ _Out_ JET_UINT32 * pcInstanceInfo,
+ _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_A ** paInstanceInfo,
+ _In_ const JET_GRBIT grbit );
#if ( JET_VERSION >= 0x0600 )
JET_ERR JET_API
JetOSSnapshotFreezeW(
- _In_ const JET_OSSNAPID snapId,
- _Out_ unsigned long * pcInstanceInfo,
- _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_W ** paInstanceInfo,
- _In_ const JET_GRBIT grbit );
+ _In_ const JET_OSSNAPID snapId,
+ _Out_ JET_UINT32 * pcInstanceInfo,
+ _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_W ** paInstanceInfo,
+ _In_ const JET_GRBIT grbit );
#ifdef JET_UNICODE
#define JetOSSnapshotFreeze JetOSSnapshotFreezeW
@@ -11304,10 +11340,10 @@ JetOSSnapshotTruncateLogInstance(
JET_ERR JET_API
JetOSSnapshotGetFreezeInfoA(
- _In_ const JET_OSSNAPID snapId,
- _Out_ unsigned long * pcInstanceInfo,
- _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_A ** paInstanceInfo,
- _In_ const JET_GRBIT grbit );
+ _In_ const JET_OSSNAPID snapId,
+ _Out_ JET_UINT32 * pcInstanceInfo,
+ _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_A ** paInstanceInfo,
+ _In_ const JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -11317,10 +11353,10 @@ JetOSSnapshotGetFreezeInfoA(
JET_ERR JET_API
JetOSSnapshotGetFreezeInfoW(
- _In_ const JET_OSSNAPID snapId,
- _Out_ unsigned long * pcInstanceInfo,
- _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_W ** paInstanceInfo,
- _In_ const JET_GRBIT grbit );
+ _In_ const JET_OSSNAPID snapId,
+ _Out_ JET_UINT32 * pcInstanceInfo,
+ _Outptr_result_buffer_( *pcInstanceInfo ) JET_INSTANCE_INFO_W ** paInstanceInfo,
+ _In_ const JET_GRBIT grbit );
#ifdef JET_UNICODE
#define JetOSSnapshotGetFreezeInfo JetOSSnapshotGetFreezeInfoW
@@ -11346,12 +11382,12 @@ JetOSSnapshotEnd(
JET_ERR JET_API
JetGetPageInfo(
- _In_reads_bytes_( cbData ) void * const pvPages, // raw page data
- _In_ unsigned long cbData, // size of raw page data
- _Inout_updates_bytes_( cbPageInfo ) JET_PAGEINFO * rgPageInfo, // array of pageinfo structures
- _In_ unsigned long cbPageInfo, // length of buffer for pageinfo array
- _In_ JET_GRBIT grbit, // options
- _In_ unsigned long ulInfoLevel ); // info level
+ _In_reads_bytes_( cbData ) const JET_PVOID pvPages, // raw page data
+ _In_ JET_UINT32 cbData, // size of raw page data
+ _Inout_updates_bytes_( cbPageInfo ) JET_PAGEINFO * rgPageInfo, // array of pageinfo structures
+ _In_ JET_UINT32 cbPageInfo, // length of buffer for pageinfo array
+ _In_ JET_GRBIT grbit, // options
+ _In_ JET_UINT32 ulInfoLevel ); // info level
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -11365,23 +11401,23 @@ JetGetPageInfo(
JET_ERR JET_API
JetGetPageInfo2(
- _In_reads_bytes_( cbData ) void * const pvPages, // raw page data
- _In_ unsigned long cbData, // size of raw page data
- _Inout_updates_bytes_( cbPageInfo ) void * const rgPageInfo, // array of pageinfo structures
- _In_ unsigned long cbPageInfo, // length of buffer for pageinfo array
- _In_ JET_GRBIT grbit, // options
- _In_ unsigned long ulInfoLevel ); // info level
+ _In_reads_bytes_( cbData ) const JET_PVOID pvPages, // raw page data
+ _In_ JET_UINT32 cbData, // size of raw page data
+ _Inout_updates_bytes_( cbPageInfo ) const JET_PVOID rgPageInfo, // array of pageinfo structures
+ _In_ JET_UINT32 cbPageInfo, // length of buffer for pageinfo array
+ _In_ JET_GRBIT grbit, // options
+ _In_ JET_UINT32 ulInfoLevel ); // info level
JET_ERR JET_API
JetGetDatabasePages(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ unsigned long pgnoStart,
- _In_ unsigned long cpg,
- _Out_writes_bytes_to_( cb, *pcbActual ) void * pv,
- _In_ unsigned long cb,
- _Out_ unsigned long * pcbActual,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_UINT32 pgnoStart,
+ _In_ JET_UINT32 cpg,
+ _Out_writes_bytes_to_( cb, *pcbActual ) JET_PVOID pv,
+ _In_ JET_UINT32 cb,
+ _Out_ JET_UINT32 * pcbActual,
+ _In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -11397,14 +11433,14 @@ JetGetDatabasePages(
JET_ERR JET_API
JetOnlinePatchDatabasePage(
- _In_ JET_SESID sesid,
- _In_ JET_DBID dbid,
- _In_ unsigned long pgno,
- _In_reads_bytes_(cbToken) const void * pvToken,
- _In_ unsigned long cbToken,
- _In_reads_bytes_(cbData) const void * pvData,
- _In_ unsigned long cbData,
- _In_ JET_GRBIT grbit );
+ _In_ JET_SESID sesid,
+ _In_ JET_DBID dbid,
+ _In_ JET_UINT32 pgno,
+ _In_reads_bytes_(cbToken) JET_PCVOID pvToken,
+ _In_ JET_UINT32 cbToken,
+ _In_reads_bytes_(cbData) JET_PCVOID pvData,
+ _In_ JET_UINT32 cbData,
+ _In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -11442,14 +11478,14 @@ JET_ERR JET_API
JetBeginDatabaseIncrementalReseedA(
_In_ JET_INSTANCE instance,
_In_ JET_PCSTR szDatabase,
- _In_ unsigned long genFirstDivergedLog,
+ _In_ JET_UINT32 genFirstDivergedLog,
_In_ JET_GRBIT grbit );
JET_ERR JET_API
JetBeginDatabaseIncrementalReseedW(
_In_ JET_INSTANCE instance,
_In_ JET_PCWSTR szDatabase,
- _In_ unsigned long genFirstDivergedLog,
+ _In_ JET_UINT32 genFirstDivergedLog,
_In_ JET_GRBIT grbit );
#ifdef JET_UNICODE
@@ -11462,18 +11498,18 @@ JET_ERR JET_API
JetEndDatabaseIncrementalReseedA(
_In_ JET_INSTANCE instance,
_In_ JET_PCSTR szDatabase,
- _In_ unsigned long genMinRequired,
- _In_ unsigned long genFirstDivergedLog,
- _In_ unsigned long genMaxRequired,
+ _In_ JET_UINT32 genMinRequired,
+ _In_ JET_UINT32 genFirstDivergedLog,
+ _In_ JET_UINT32 genMaxRequired,
_In_ JET_GRBIT grbit );
JET_ERR JET_API
JetEndDatabaseIncrementalReseedW(
_In_ JET_INSTANCE instance,
_In_ JET_PCWSTR szDatabase,
- _In_ unsigned long genMinRequired,
- _In_ unsigned long genFirstDivergedLog,
- _In_ unsigned long genMaxRequired,
+ _In_ JET_UINT32 genMinRequired,
+ _In_ JET_UINT32 genFirstDivergedLog,
+ _In_ JET_UINT32 genMaxRequired,
_In_ JET_GRBIT grbit );
#ifdef JET_UNICODE
@@ -11484,23 +11520,23 @@ JetEndDatabaseIncrementalReseedW(
JET_ERR JET_API
JetPatchDatabasePagesA(
- _In_ JET_INSTANCE instance,
- _In_ JET_PCSTR szDatabase,
- _In_ unsigned long pgnoStart,
- _In_ unsigned long cpg,
- _In_reads_bytes_( cb ) const void * pv,
- _In_ unsigned long cb,
- _In_ JET_GRBIT grbit );
+ _In_ JET_INSTANCE instance,
+ _In_ JET_PCSTR szDatabase,
+ _In_ JET_UINT32 pgnoStart,
+ _In_ JET_UINT32 cpg,
+ _In_reads_bytes_( cb ) JET_PCVOID pv,
+ _In_ JET_UINT32 cb,
+ _In_ JET_GRBIT grbit );
JET_ERR JET_API
JetPatchDatabasePagesW(
- _In_ JET_INSTANCE instance,
- _In_ JET_PCWSTR szDatabase,
- _In_ unsigned long pgnoStart,
- _In_ unsigned long cpg,
- _In_reads_bytes_( cb ) const void * pv,
- _In_ unsigned long cb,
- _In_ JET_GRBIT grbit );
+ _In_ JET_INSTANCE instance,
+ _In_ JET_PCWSTR szDatabase,
+ _In_ JET_UINT32 pgnoStart,
+ _In_ JET_UINT32 cpg,
+ _In_reads_bytes_( cb ) JET_PCVOID pv,
+ _In_ JET_UINT32 cb,
+ _In_ JET_GRBIT grbit );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
#pragma endregion
@@ -11518,17 +11554,17 @@ JetPatchDatabasePagesW(
JET_ERR JET_API
JetGetRBSFileInfoA(
- _In_ JET_PCSTR szRBSFileName,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_PCSTR szRBSFileName,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
JET_ERR JET_API
JetGetRBSFileInfoW(
- _In_ JET_PCWSTR szRBSFileName,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel );
+ _In_ JET_PCWSTR szRBSFileName,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel );
#ifdef JET_UNICODE
#define JetGetRBSFileInfo JetGetRBSFileInfoW
@@ -11540,15 +11576,15 @@ JET_ERR JET_API
JetRBSPrepareRevert(
_In_ JET_INSTANCE instance,
_In_ JET_LOGTIME jltRevertExpected,
- _In_ long cpgCache,
+ _In_ JET_INT32 cpgCache,
_In_ JET_GRBIT grbit,
- _Out_ JET_LOGTIME* pjltRevertActual );
+ _Out_ JET_LOGTIME * pjltRevertActual );
JET_ERR JET_API
JetRBSExecuteRevert(
- _In_ JET_INSTANCE instance,
- _In_ JET_GRBIT grbit,
- _Out_ JET_RBSREVERTINFOMISC* prbsrevertinfomisc );
+ _In_ JET_INSTANCE instance,
+ _In_ JET_GRBIT grbit,
+ _Out_ JET_RBSREVERTINFOMISC * prbsrevertinfomisc );
JET_ERR JET_API
JetRBSCancelRevert(
@@ -11671,8 +11707,8 @@ enum
typedef struct tagJET_TESTHOOKUNITTEST2
{
- unsigned long cbStruct; // size of this structure
- char * szTestName; // test name / test wildcard
+ JET_UINT32 cbStruct; // size of this structure
+ JET_PSTR szTestName; // test name / test wildcard
JET_DBID dbidTestOn; // database to perform the internal tests against
} JET_TESTHOOKUNITTEST2;
@@ -11704,11 +11740,11 @@ typedef enum
// pv struct for opTestHookTestInjection
typedef struct tagJET_TESTHOOKTESTINJECTION
{
- unsigned long cbStruct;
- unsigned long ulID;
+ JET_UINT32 cbStruct;
+ JET_UINT32 ulID;
JET_API_PTR pv;
JET_TESTINJECTIONTYPE type;
- unsigned long ulProbability;
+ JET_UINT32 ulProbability;
JET_GRBIT grbit;
} JET_TESTHOOKTESTINJECTION;
@@ -11716,40 +11752,40 @@ typedef struct tagJET_TESTHOOKTESTINJECTION
// and opTestHookHookGlobalMemoryStatus
typedef struct tagJET_TESTHOOKAPIHOOKING
{
- unsigned long cbStruct;
- const void * pfnOld;
- const void * pfnNew;
+ JET_UINT32 cbStruct;
+ JET_PCVOID pfnOld;
+ JET_PCVOID pfnNew;
} JET_TESTHOOKAPIHOOKING;
// pv struct for opTestHookTraceTestMarker
typedef struct tagJET_TESTHOOKTRACETESTMARKER
{
- unsigned long cbStruct;
- const char * szAnnotation;
- unsigned __int64 qwMarkerID;
+ JET_UINT32 cbStruct;
+ JET_PCSTR szAnnotation;
+ JET_UINT64 qwMarkerID;
} JET_TESTHOOKTRACETESTMARKER;
// pv struct for opTestHookSetEngineTickTime
typedef struct tagJET_TESTHOOKTIMEINJECTION
{
- unsigned long cbStruct;
- unsigned long tickNow;
- unsigned long eTimeInjWrapMode;
- unsigned long dtickTimeInjWrapOffset;
- unsigned long dtickTimeInjAccelerant;
+ JET_UINT32 cbStruct;
+ JET_UINT32 tickNow;
+ JET_UINT32 eTimeInjWrapMode;
+ JET_UINT32 dtickTimeInjWrapOffset;
+ JET_UINT32 dtickTimeInjAccelerant;
} JET_TESTHOOKTIMEINJECTION;
// pv struct for opTestHookCacheQuery
typedef struct tagJET_TESTHOOKCACHEQUERY
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
// in args
- long cCacheQuery;
- char ** rgszCacheQuery;
+ JET_INT32 cCacheQuery;
+ JET_PSTR * rgszCacheQuery;
// out arg
- void * pvOut;
+ JET_PVOID pvOut;
} JET_TESTHOOKCACHEQUERY;
#define JET_bitTestHookEvictDataByPgno 0x00000001 // Specifies that we are evicting data from the database cache, specified by pgno.
@@ -11757,7 +11793,7 @@ typedef struct tagJET_TESTHOOKCACHEQUERY
// pv struct for opTestHookEvictCache
typedef struct tagJET_TESTHOOKEVICTCACHE
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_API_PTR ulTargetContext; // For ..EvictDataByPgno = JET_DBID
JET_API_PTR ulTargetData; // For ..EvictDataByPgno = PageNumber/pgno
JET_GRBIT grbit;
@@ -11794,7 +11830,7 @@ typedef struct tagJET_TESTHOOKEVICTCACHE
typedef struct tagJET_TESTHOOKCORRUPT
{
- unsigned long cbStruct;
+ JET_UINT32 cbStruct;
JET_GRBIT grbit;
union
@@ -11803,18 +11839,18 @@ typedef struct tagJET_TESTHOOKCORRUPT
#include
struct // CorruptDatabaseFile
{
- JET_PWSTR wszDatabaseFilePath; // Name of the database file
- __int64 pgnoTarget; // Page number target, or JET_pgnoTestHookCorruptRandom
- __int64 iSubTarget; // Depends upon the JET_bitTestHookCorruptPage* type.
+ JET_PWSTR wszDatabaseFilePath; // Name of the database file
+ JET_INT64 pgnoTarget; // Page number target, or JET_pgnoTestHookCorruptRandom
+ JET_INT64 iSubTarget; // Depends upon the JET_bitTestHookCorruptPage* type.
} CorruptDatabaseFile;
#include
struct // CorruptDatabasePageImage
{
- JET_API_PTR pbPageImageTarget; // Pointer to the page image to corrupt
- unsigned long cbPageImage;
- __int64 pgnoTarget; // Page number target (note: this may not seem like it should be required, but it is b/c 4 KB pages xor this into the checksum)
- __int64 iSubTarget; // Depends upon the JET_bitTestHookCorruptPage* type.
+ JET_API_PTR pbPageImageTarget; // Pointer to the page image to corrupt
+ JET_UINT32 cbPageImage;
+ JET_INT64 pgnoTarget; // Page number target (note: this may not seem like it should be required, but it is b/c 4 KB pages xor this into the checksum)
+ JET_INT64 iSubTarget; // Depends upon the JET_bitTestHookCorruptPage* type.
} CorruptDatabasePageImage;
};
@@ -11833,9 +11869,9 @@ typedef struct tagJET_TESTHOOKCORRUPT
typedef struct tagJET_TESTHOOKALTERDBFILEHDR
{
JET_PWSTR szDatabase;
- unsigned long ibField;
- unsigned long cbField;
- char * pbField;
+ JET_UINT32 ibField;
+ JET_UINT32 cbField;
+ JET_BYTE * pbField;
JET_GRBIT grbit;
} JET_TESTHOOKALTERDBFILEHDR;
@@ -11845,14 +11881,14 @@ typedef struct tagJET_TESTHOOKALTERDBFILEHDR
JET_ERR JET_API JetTestHook(
_In_ const TESTHOOK_OP opcode,
- _Inout_opt_ void * const pv );
+ _Inout_opt_ const JET_PVOID pv );
JET_ERR JET_API JetConsumeLogData(
_In_ JET_INSTANCE instance,
_In_ JET_EMITDATACTX * pEmitLogDataCtx,
- _In_ void * pvLogData,
- _In_ unsigned long cbLogData,
+ _In_ JET_PVOID pvLogData,
+ _In_ JET_UINT32 cbLogData,
_In_ JET_GRBIT grbits );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
@@ -11868,11 +11904,11 @@ JET_ERR JET_API JetConsumeLogData(
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT)
JET_ERR JET_API JetGetErrorInfoW(
- _In_opt_ void * pvContext,
- _Out_writes_bytes_( cbMax ) void * pvResult,
- _In_ unsigned long cbMax,
- _In_ unsigned long InfoLevel,
- _In_ JET_GRBIT grbit );
+ _In_opt_ JET_PVOID pvContext,
+ _Out_writes_bytes_( cbMax ) JET_PVOID pvResult,
+ _In_ JET_UINT32 cbMax,
+ _In_ JET_UINT32 InfoLevel,
+ _In_ JET_GRBIT grbit );
#ifdef JET_UNICODE
#define JetGetErrorInfo JetGetErrorInfoW
@@ -11883,17 +11919,17 @@ JET_ERR JET_API JetGetErrorInfoW(
JET_ERR JET_API
JetSetSessionParameter(
_In_opt_ JET_SESID sesid,
- _In_ unsigned long sesparamid,
- _In_reads_bytes_opt_( cbParam ) void * pvParam,
- _In_ unsigned long cbParam );
+ _In_ JET_UINT32 sesparamid,
+ _In_reads_bytes_opt_( cbParam ) JET_PVOID pvParam,
+ _In_ JET_UINT32 cbParam );
JET_ERR JET_API
JetGetSessionParameter(
_In_opt_ JET_SESID sesid,
- _In_ unsigned long sesparamid,
- _Out_cap_post_count_(cbParamMax, *pcbParamActual) void * pvParam,
- _In_ unsigned long cbParamMax,
- _Out_opt_ unsigned long * pcbParamActual );
+ _In_ JET_UINT32 sesparamid,
+ _Out_cap_post_count_(cbParamMax, *pcbParamActual) JET_PVOID pvParam,
+ _In_ JET_UINT32 cbParamMax,
+ _Out_opt_ JET_UINT32 * pcbParamActual );
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_PKG_ESENT) */
#pragma endregion
@@ -11907,7 +11943,7 @@ JET_ERR JET_API JetPrereadTablesW(
_In_ JET_SESID sesid,
_In_ JET_DBID dbid,
_In_reads_( cwszTables ) JET_PCWSTR * rgwszTables,
- _In_ long cwszTables,
+ _In_ JET_INT32 cwszTables,
_In_ JET_GRBIT grbit );
#ifdef JET_UNICODE
@@ -11932,35 +11968,35 @@ JetPrereadIndexRange(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
_In_ const JET_INDEX_RANGE * const pIndexRange,
- _In_ const unsigned long cPageCacheMin,
- _In_ const unsigned long cPageCacheMax,
+ _In_ const JET_UINT32 cPageCacheMin,
+ _In_ const JET_UINT32 cPageCacheMax,
_In_ JET_GRBIT grbit,
- _Out_opt_ unsigned long * const pcPageCacheActual );
+ _Out_opt_ JET_UINT32 * const pcPageCacheActual );
#endif // JET_VERSION >= 0x0A00
#if ( JET_VERSION >= 0x0A01 )
JET_ERR JET_API JetRetrieveColumnByReference(
- _In_ const JET_SESID sesid,
- _In_ const JET_TABLEID tableid,
- _In_reads_bytes_( cbReference ) const void * const pvReference,
- _In_ const unsigned long cbReference,
- _In_ const unsigned long ibData,
- _Out_writes_bytes_to_opt_( cbData, min( cbData, *pcbActual ) ) void * const pvData,
- _In_ const unsigned long cbData,
- _Out_opt_ unsigned long * const pcbActual,
- _In_ const JET_GRBIT grbit );
+ _In_ const JET_SESID sesid,
+ _In_ const JET_TABLEID tableid,
+ _In_reads_bytes_( cbReference ) const JET_PCVOID pvReference,
+ _In_ const JET_UINT32 cbReference,
+ _In_ const JET_UINT32 ibData,
+ _Out_writes_bytes_to_opt_( cbData, min( cbData, *pcbActual ) ) const JET_PVOID pvData,
+ _In_ const JET_UINT32 cbData,
+ _Out_opt_ JET_UINT32 * const pcbActual,
+ _In_ const JET_GRBIT grbit );
JET_ERR JET_API JetPrereadColumnsByReference(
_In_ const JET_SESID sesid,
_In_ const JET_TABLEID tableid,
- _In_reads_( cReferences ) const void * const * const rgpvReferences,
- _In_reads_( cReferences ) const unsigned long * const rgcbReferences,
- _In_ const unsigned long cReferences,
- _In_ const unsigned long cPageCacheMin,
- _In_ const unsigned long cPageCacheMax,
- _Out_opt_ unsigned long * const pcReferencesPreread,
+ _In_reads_( cReferences ) const JET_PCVOID * const rgpvReferences,
+ _In_reads_( cReferences ) const JET_UINT32 * const rgcbReferences,
+ _In_ const JET_UINT32 cReferences,
+ _In_ const JET_UINT32 cPageCacheMin,
+ _In_ const JET_UINT32 cPageCacheMax,
+ _Out_opt_ JET_UINT32 * const pcReferencesPreread,
_In_ const JET_GRBIT grbit );
#endif // JET_VERSION >= 0x0A01
@@ -11970,21 +12006,21 @@ JET_ERR JET_API JetPrereadColumnsByReference(
JET_ERR JET_API JetStreamRecords(
_In_ JET_SESID sesid,
_In_ JET_TABLEID tableid,
- _In_ const unsigned long ccolumnid,
+ _In_ const JET_UINT32 ccolumnid,
_In_reads_opt_( ccolumnid ) const JET_COLUMNID * const rgcolumnid,
- _Out_writes_bytes_to_opt_( cbData, *pcbActual ) void * const pvData,
- _In_ const unsigned long cbData,
- _Out_opt_ unsigned long * const pcbActual,
+ _Out_writes_bytes_to_opt_( cbData, *pcbActual ) const JET_PVOID pvData,
+ _In_ const JET_UINT32 cbData,
+ _Out_opt_ JET_UINT32 * const pcbActual,
_In_ const JET_GRBIT grbit );
JET_ERR JET_API JetRetrieveColumnFromRecordStream(
- _Inout_updates_bytes_( cbData ) void * const pvData,
- _In_ const unsigned long cbData,
- _Out_ unsigned long * const piRecord,
+ _Inout_updates_bytes_( cbData ) const JET_PVOID pvData,
+ _In_ const JET_UINT32 cbData,
+ _Out_ JET_UINT32 * const piRecord,
_Out_ JET_COLUMNID * const pcolumnid,
- _Out_ unsigned long * const pitagSequence,
- _Out_ unsigned long * const pibValue,
- _Out_ unsigned long * const pcbValue );
+ _Out_ JET_UINT32 * const pitagSequence,
+ _Out_ JET_UINT32 * const pibValue,
+ _Out_ JET_UINT32 * const pcbValue );
#endif // JET_VERSION >= 0x0A01
diff --git a/dev/ese/published/inc/os.hxx b/dev/ese/published/inc/os.hxx
index 8c693286..31144af3 100644
--- a/dev/ese/published/inc/os.hxx
+++ b/dev/ese/published/inc/os.hxx
@@ -261,4 +261,14 @@ BOOL FOSLayerUp();
//#define wcslen __USE_LOSSTRLENGTHW__
#endif
+#if 0
+// These are too difficult to get working in test code and
+// downstream build locations that include the OS abstraction
+// but don't necessarily directly use it. So don't leave them
+// turned on. However, leave them here to turn on in an
+// ad-hoc manner.
+#pragma deprecated( "wcscmp" )
+#pragma deprecated( "wcslen" )
+#endif
+
#endif // _OS_HXX_INCLUDED
diff --git a/dev/ese/published/inc/os/cprintf.hxx b/dev/ese/published/inc/os/cprintf.hxx
index 323db650..097d3cc4 100644
--- a/dev/ese/published/inc/os/cprintf.hxx
+++ b/dev/ese/published/inc/os/cprintf.hxx
@@ -6,7 +6,7 @@
#include
-
+#include
// ==================================================================================================================
class CPRINTF
@@ -16,10 +16,10 @@ class CPRINTF
CPRINTF() {}
virtual ~CPRINTF() {}
- static void SetThreadPrintfPrefix( _In_ const _TCHAR * szPrefix );
+ static void SetThreadPrintfPrefix( _In_ const CHAR * szPrefix );
public:
- virtual void __cdecl operator()( const _TCHAR* szFormat, ... ) = 0;
+ virtual void __cdecl operator()( const CHAR* szFormat, ... ) = 0;
};
// ==================================================================================================================
@@ -27,12 +27,12 @@ class CPRINTFNULL : public CPRINTF
// ==================================================================================================================
{
public:
- void __cdecl operator()( const _TCHAR* szFormat, ... );
+ void __cdecl operator()( const CHAR* szFormat, ... );
static CPRINTF* PcprintfInstance();
};
// ================================================================
-INLINE void __cdecl CPRINTFNULL::operator()( const _TCHAR* szFormat, ... )
+INLINE void __cdecl CPRINTFNULL::operator()( const CHAR* szFormat, ... )
// ================================================================
{
va_list arg_ptr;
@@ -58,7 +58,7 @@ class CPRINTFDBGOUT : public CPRINTF
//-
{
public:
- void __cdecl operator()( const _TCHAR* szFormat, ... );
+ void __cdecl operator()( const CHAR* szFormat, ... );
static CPRINTF* PcprintfInstance();
};
@@ -68,7 +68,7 @@ class CPRINTFSTDOUT : public CPRINTF
// ==================================================================================================================
{
public:
- void __cdecl operator()( const _TCHAR* szFormat, ... );
+ void __cdecl operator()( const CHAR* szFormat, ... );
static CPRINTF* PcprintfInstance();
};
@@ -81,12 +81,12 @@ INLINE CPRINTF* CPRINTFSTDOUT::PcprintfInstance()
}
// ================================================================
-INLINE void __cdecl CPRINTFSTDOUT::operator()( const _TCHAR* szFormat, ... )
+INLINE void __cdecl CPRINTFSTDOUT::operator()( const CHAR* szFormat, ... )
// ================================================================
{
va_list arg_ptr;
va_start( arg_ptr, szFormat );
- _vtprintf( szFormat, arg_ptr );
+ vprintf( szFormat, arg_ptr );
va_end( arg_ptr );
}
@@ -97,14 +97,14 @@ class CPRINTINTRINBUF : public CPRINTF
{
public:
CPRINTINTRINBUF();
-
+
virtual void Reset();
virtual BOOL FContains( _In_z_ const CHAR * const szFind );
virtual ULONG CContains( _In_z_ const CHAR * const szFind );
void Print( CPRINTF & pcprintf );
- void __cdecl operator()( const _TCHAR* szFormat, ... );
+ void __cdecl operator()( const CHAR* szFormat, ... );
private:
// probably should templatize this buffer size.
@@ -199,14 +199,14 @@ INLINE void CPRINTINTRINBUF::Reset()
}
// ================================================================
-INLINE void __cdecl CPRINTINTRINBUF::operator()( const _TCHAR* szFormat, ... )
+INLINE void __cdecl CPRINTINTRINBUF::operator()( const CHAR* szFormat, ... )
// ================================================================
{
CHAR rgchBuf[ 1024 ];
va_list arg_ptr;
va_start( arg_ptr, szFormat );
- StringCbVPrintfA( rgchBuf, sizeof( rgchBuf ), (CHAR*)szFormat, arg_ptr );
+ OSStrCbVFormatA( rgchBuf, sizeof( rgchBuf ), (CHAR*)szFormat, arg_ptr );
va_end( arg_ptr );
Append_( rgchBuf );
@@ -298,9 +298,9 @@ INLINE void CPRINTINTRINBUF::Print( CPRINTF & cprintf )
while( ( szT = csr.SzNext() ) != NULL )
{
if ( fSzId )
- cprintf( (_TCHAR*)"[%d] %hs", i, szT );
+ cprintf( (CHAR*)"[%d] %hs", i, szT );
else
- cprintf( (_TCHAR*)"%hs", szT );
+ cprintf( (CHAR*)"%hs", szT );
i++;
}
}
@@ -312,7 +312,7 @@ class CPRINTFDEBUG : public CPRINTF
// ==================================================================================================================
{
public:
- void __cdecl operator()( const _TCHAR* szFormat, ... );
+ void __cdecl operator()( const CHAR* szFormat, ... );
static CPRINTF* PcprintfInstance();
};
@@ -325,12 +325,12 @@ INLINE CPRINTF* CPRINTFDEBUG::PcprintfInstance()
}
// ================================================================
-INLINE void __cdecl CPRINTFDEBUG::operator()( const _TCHAR* szFormat, ... )
+INLINE void __cdecl CPRINTFDEBUG::operator()( const CHAR* szFormat, ... )
// ================================================================
{
va_list arg_ptr;
va_start( arg_ptr, szFormat );
- _vtprintf( szFormat, arg_ptr );
+ vprintf( szFormat, arg_ptr );
va_end( arg_ptr );
}
@@ -343,35 +343,26 @@ class CPRINTFFILE : public CPRINTF
// ==================================================================================================================
{
public:
- CPRINTFFILE( const WCHAR* wszFile );
- ~CPRINTFFILE();
-
- void __cdecl operator()( const _TCHAR* szFormat, ... );
+ enum FILEENCODING
+ {
+ ASCII,
+ UTF16
+ };
- private:
- void* m_hFile;
- void* m_hMutex;
-};
+ CPRINTFFILE( const WCHAR* wszFile, FILEENCODING eEncoding );
+ ~CPRINTFFILE();
+
+ void __cdecl operator()( const CHAR* szFormat, ... );
+ void __cdecl operator()( const WCHAR * wszFormat, ... );
+
+ ERR m_errLast;
-// ==================================================================================================================
-class CWPRINTFFILE : public CPRINTF
-// ==================================================================================================================
-{
- public:
- CWPRINTFFILE( const WCHAR* szFile );
- ~CWPRINTFFILE();
-
- // If _UNICODE is defined, then we only want a single function.
- // If _UNICODE is not defined, we need two different functions.
-#ifndef _UNICODE
- void __cdecl operator()( const _TCHAR* szFormat, ... );
-#endif
- void __cdecl operator()( const wchar_t * wszFormat, ... );
- ERR m_errLast;
-
private:
+ void __cdecl CPRINTFFILE::PutBytesInFile_( BYTE *pb, ULONG cb );
+ void __cdecl CPRINTFFILE::VerifyOnlyDOSTextFileLineReturns_( PCWSTR wsz );
void* m_hFile;
void* m_hMutex;
+ FILEENCODING m_feEncodingType;
};
// ==================================================================================================================
@@ -379,51 +370,51 @@ class CPRINTFINDENT : public CPRINTF
// ==================================================================================================================
{
public:
- CPRINTFINDENT( CPRINTF* pcprintf, const _TCHAR* szPrefix = NULL );
-
- void __cdecl operator()( const _TCHAR* szFormat, ... );
+ CPRINTFINDENT( CPRINTF* pcprintf, const CHAR* szPrefix = NULL );
+
+ void __cdecl operator()( const CHAR* szFormat, ... );
virtual void Indent();
virtual void Unindent();
-
+
protected:
CPRINTFINDENT();
-
+
private:
CPRINTF* const m_pcprintf;
INT m_cindent;
- const _TCHAR* const m_szPrefix;
+ const CHAR* const m_szPrefix;
};
// ================================================================
-INLINE CPRINTFINDENT::CPRINTFINDENT( CPRINTF* pcprintf, const _TCHAR* szPrefix ) :
+INLINE CPRINTFINDENT::CPRINTFINDENT( CPRINTF* pcprintf, const CHAR* szPrefix ) :
// ================================================================
m_cindent( 0 ),
m_pcprintf( pcprintf ),
m_szPrefix( szPrefix )
{
}
-
+
// ================================================================
-INLINE void __cdecl CPRINTFINDENT::operator()( const _TCHAR* szFormat, ... )
+INLINE void __cdecl CPRINTFINDENT::operator()( const CHAR* szFormat, ... )
// ================================================================
{
- _TCHAR rgchBuf[1024];
+ CHAR rgchBuf[1024];
va_list arg_ptr;
va_start( arg_ptr, szFormat );
- StringCbVPrintf( rgchBuf, sizeof(rgchBuf), szFormat, arg_ptr );
+ OSStrCbVFormatA( rgchBuf, sizeof(rgchBuf), szFormat, arg_ptr );
va_end( arg_ptr );
for( INT i = 0; i < m_cindent; i++ )
{
- (*m_pcprintf)( _T( "\t" ) );
+ (*m_pcprintf)( "\t" );
}
if( m_szPrefix )
{
- (*m_pcprintf)( _T( "%s" ), m_szPrefix );
+ (*m_pcprintf)( "%s", m_szPrefix );
}
- (*m_pcprintf)( _T( "%s" ), rgchBuf );
+ (*m_pcprintf)( "%s", rgchBuf );
}
// ================================================================
@@ -451,7 +442,7 @@ INLINE CPRINTFINDENT::CPRINTFINDENT( ) :
m_szPrefix( 0 )
{
}
-
+
// ==================================================================================================================
class CPRINTFTLSPREFIX : public CPRINTFINDENT
@@ -463,17 +454,17 @@ class CPRINTFTLSPREFIX : public CPRINTFINDENT
//-
{
public:
- CPRINTFTLSPREFIX( CPRINTF* pcprintf, const _TCHAR * const szPrefix = NULL );
-
- void __cdecl operator()( const _TCHAR* szFormat, ... );
+ CPRINTFTLSPREFIX( CPRINTF* pcprintf, const CHAR * const szPrefix = NULL );
+
+ void __cdecl operator()( const CHAR* szFormat, ... );
void Indent();
void Unindent();
-
+
private:
CPRINTF* const m_pcprintf;
INT m_cindent;
- const _TCHAR* const m_szPrefix;
+ const CHAR* const m_szPrefix;
};
@@ -482,25 +473,25 @@ class CPRINTFFN : public CPRINTF
// ==================================================================================================================
{
public:
- CPRINTFFN( INT (__cdecl *pfnPrintf)(const _TCHAR*, ... ) ) : m_pfnPrintf( pfnPrintf ) {}
+ CPRINTFFN( INT (__cdecl *pfnPrintf)(const CHAR*, ... ) ) : m_pfnPrintf( pfnPrintf ) {}
~CPRINTFFN() {}
- void __cdecl operator()( const _TCHAR* szFormat, ... )
+ void __cdecl operator()( const CHAR* szFormat, ... )
{
- _TCHAR rgchBuf[1024];
-
+ CHAR rgchBuf[1024];
+
va_list arg_ptr;
va_start( arg_ptr, szFormat );
- StringCbVPrintf(rgchBuf, sizeof(rgchBuf), szFormat, arg_ptr);
+ OSStrCbVFormatA(rgchBuf, sizeof(rgchBuf), szFormat, arg_ptr);
va_end( arg_ptr );
- (*m_pfnPrintf)( _T( "%s" ), rgchBuf );
+ (*m_pfnPrintf)( "%s", rgchBuf );
}
private:
- INT (__cdecl *m_pfnPrintf)( const _TCHAR*, ... );
+ INT (__cdecl *m_pfnPrintf)( const CHAR*, ... );
};
-
+
// retrieves the current width of stdout
diff --git a/dev/ese/published/inc/os/edbg.hxx b/dev/ese/published/inc/os/edbg.hxx
index 342bf0fc..bed50ac0 100644
--- a/dev/ese/published/inc/os/edbg.hxx
+++ b/dev/ese/published/inc/os/edbg.hxx
@@ -38,12 +38,6 @@ struct EDBGGlobals
// as a pointer of a different name.
extern const EDBGGlobals * rgEDBGGlobalsArray;
-HRESULT
-EDBGPrintf(
- _In_ PCSTR szFormat,
- ...
-)
-;
#endif // DEBUGGER_EXTENSION
diff --git a/dev/ese/published/inc/os/encrypt.hxx b/dev/ese/published/inc/os/encrypt.hxx
index 0d82c89e..9df20f87 100644
--- a/dev/ese/published/inc/os/encrypt.hxx
+++ b/dev/ese/published/inc/os/encrypt.hxx
@@ -9,30 +9,41 @@ Crc32Checksum(
_In_reads_bytes_( cbData ) const BYTE *pbData,
_In_ ULONG cbData );
+ULONG CbOSEncryptAes256SizeNeeded( ULONG cbDataLen );
+
+enum AES256_IMPLEMENTATION
+{
+ AES256_CAPI_IMPLEMENTATION,
+ AES256_CNG_IMPLEMENTATION
+};
+
ERR
ErrOSCreateAes256Key(
+ _In_ AES256_IMPLEMENTATION impl,
_Out_writes_bytes_to_opt_(*pcbKeySize, *pcbKeySize) BYTE *pbKey,
_Inout_ ULONG *pcbKeySize );
-ULONG CbOSEncryptAes256SizeNeeded( ULONG cbDataLen );
-
-ERR ErrOSEncryptionVerifyKey(
- _In_reads_bytes_(cbKey) const BYTE *pbKey,
- _In_ ULONG cbKey );
+ERR
+ErrOSEncryptionVerifyKey(
+ _In_ AES256_IMPLEMENTATION impl,
+ _In_reads_bytes_(cbKey) const BYTE *pbKey,
+ _In_ ULONG cbKey );
// Encrypt using AES256 encryption in CBC mode with PKCS5 padding.
// Also, there is initial padding for checksum, InitVector in the output data.
// Use CbOSEncryptAes256SizeNeeded above to figure out how big the output buffer needs to be.
ERR
ErrOSEncryptWithAes256(
- _Inout_updates_bytes_to_(cbDataBufLen, *pcbDataLen) BYTE *pbData,
- _Inout_ ULONG *pcbDataLen,
- _In_ ULONG cbDataBufLen,
- _In_reads_bytes_(cbKey) const BYTE *pbKey,
- _In_ ULONG cbKey );
+ _In_ AES256_IMPLEMENTATION impl,
+ _Inout_updates_bytes_to_(cbDataBufLen, *pcbDataLen) BYTE *pbData,
+ _Inout_ ULONG *pcbDataLen,
+ _In_ ULONG cbDataBufLen,
+ _In_reads_bytes_(cbKey) const BYTE *pbKey,
+ _In_ ULONG cbKey );
ERR
ErrOSDecryptWithAes256(
+ _In_ AES256_IMPLEMENTATION impl,
_In_reads_( *pcbDataLen ) BYTE *pbDataIn,
_Out_writes_bytes_to_(*pcbDataLen, *pcbDataLen) BYTE *pbDataOut,
_Inout_ ULONG *pcbDataLen,
diff --git a/dev/ese/published/inc/os/error.hxx b/dev/ese/published/inc/os/error.hxx
index cd234fef..ee00debf 100644
--- a/dev/ese/published/inc/os/error.hxx
+++ b/dev/ese/published/inc/os/error.hxx
@@ -22,13 +22,9 @@ const CHAR * SzSourceFileName( const CHAR * szFilePath );
// Prototypes
//
-#ifdef DEBUG
-
-// IsDebuggerAttached() is useful to silence Asserts. It shouldn't be used in
-// retail code.
+// indicates if a user mode debugger is attached to this process
BOOL IsDebuggerAttached();
-#endif
// ------------------------------------------------------------------------------------------------
@@ -373,41 +369,6 @@ extern void (__stdcall *g_pfnEnforceContextFail)( const WCHAR* wszContext, const
#define EnforceSz( exp, szTag ) EnforceAtSz( exp, szTag, __FILE__, __LINE__ )
-// ------------------------------------------------------------------------------------------------
-//
-// Compiler Assert
-//
-
-//
-// C_ASSERT() can be used to perform many compile-time assertions:
-// type sizes, field offsets, etc.
-//
-// An assertion failure results in
-// error C2118: negative subscript.
-// If you have not defined a static / compile-time constraint results in
-// error C3861: 'countof': identifier not found
-// error C2086: 'char __C_ASSERT__[1]' : redefinition
-//
-// Copied over from winnt.h
-
-#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
-// This C_ASSERT() is not sufficient for a check like this:
-// C_ASSERT( dtickMaintCacheSizeRequest <= dtickMaintCacheStatsPeriod / 2 );
-// b/c (at the time) dtickMaintCacheSizeRequest = 0, and so the error
-// 2>e:\src\win8\esent2\ds\esent\src\ese\bf.cxx(11397) : error C4296: '<=' : expression is always true
-// is returned. It is complaining that "0 <= x" ... no value of x can ever
-// make this false ... but since 0 can change (b/c it's a constant that may
-// be altered) this is actually a valid C_ASSERT().
-
-// Doing a better C_ASSERT() ...
-#define S_ASSERT(e) \
- __pragma(warning(push)) \
- __pragma(warning(disable:4296)) \
- typedef char __C_ASSERT__[(e)?1:-1] \
- __pragma(warning(pop))
-
-
-
// ------------------------------------------------------------------------------------------------
//
// Exceptions
@@ -527,12 +488,6 @@ public:
__forceinline CErrFrameSimple * PefLastThrow();
-__forceinline ERR ErrERRSetLastThrow( _In_ const CHAR* szFile, _In_ const LONG lLine, _In_ const ERR err )
-{
- PefLastThrow()->Set( szFile, lLine, err );
- return err;
-}
-
// Returns the line of the last call that failed out w/ an error, presumably within this frame.
ULONG UlLineLastCall();
@@ -573,7 +528,10 @@ ERR ErrERRCheck_( const ERR err, const CHAR* szFile, const LONG lLine );
__forceinline ERR ErrERRCheck_( _In_ const ERR err, _In_ const CHAR* szFile, _In_ const LONG lLine )
{
extern ERR g_errTrap;
- PefLastThrow()->Set( szFile, lLine, err );
+ if ( err < 0 /* JET_errSuccess */ )
+ {
+ PefLastThrow()->Set( szFile, lLine, err );
+ }
if ( g_errTrap == err )
{
KernelDebugBreakPoint();
diff --git a/dev/ese/published/inc/os/hapublish.hxx b/dev/ese/published/inc/os/hapublish.hxx
index 93929b87..a1118032 100644
--- a/dev/ese/published/inc/os/hapublish.hxx
+++ b/dev/ese/published/inc/os/hapublish.hxx
@@ -8,6 +8,11 @@
#include
#include "exdbmsg_ese.h"
+const DWORD bitHaPublishedEvent = 0x1;
+const DWORD bitHaPublishedCorruptionTag = 0x2;
+const DWORD bitHaPublishedIoHardTag = 0x4;
+const DWORD bitHaPublishedLogLogicallyInconsistentTag = 0x2;
+
#define Ese2HaId( id ) ( HADBFAILURE_EVENT_RANGE_START_ESE + ( id ) )
#define OSUHAPublishEvent( p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 ) \
diff --git a/dev/ese/published/inc/os/math.hxx b/dev/ese/published/inc/os/math.hxx
index 9b2e9d54..37d8fd03 100644
--- a/dev/ese/published/inc/os/math.hxx
+++ b/dev/ese/published/inc/os/math.hxx
@@ -21,7 +21,7 @@
// Power-of-2 related helpers.
template
-inline bool FPowerOf2( T x )
+constexpr inline bool FPowerOf2( T x )
{
return ( ( 0 < x ) && ( 0 == ( x & ( x - 1 ) ) ) );
}
@@ -38,7 +38,7 @@ inline ULONG Log2( ULONG x )
inline ULONG Log2( unsigned __int64 x )
{
ULONG log2;
- BYTE ret = _BitScanReverse64( &log2, x );
+ BYTE ret = _BitScanReverse64( ( OS_WIN_ULONG * )&log2, x );
return ret > 0 ? log2 : -1; // log( 0 ) is undefined, represented by -1
}
@@ -69,6 +69,13 @@ inline USHORT UsBits( const DWORD dw )
return (USHORT)ret;
}
+inline ULONG Log2OfPowerOf2( ULONG x )
+{
+ ULONG index;
+ _BitScanForward( &index, x );
+ return index;
+}
+
#pragma warning (push)
#pragma warning (disable: 4293) // '>>': shift count negative or too big, undefined behavior
diff --git a/dev/ese/published/inc/os/memfile.hxx b/dev/ese/published/inc/os/memfile.hxx
index 521ec8e8..efc3676f 100644
--- a/dev/ese/published/inc/os/memfile.hxx
+++ b/dev/ese/published/inc/os/memfile.hxx
@@ -40,7 +40,7 @@ public:
ERR ErrRetrieveAllocatedRegion( const QWORD ibOffsetToQuery,
_Out_ QWORD* const pibStartTrimmedRegion,
_Out_ QWORD* const pcbTrimmed ) override { AssertSz( fFalse, "NYI!" ); return ErrERRCheck( JET_errNyi ); }
- ERR ErrFlushFileBuffers( const IOFLUSHREASON iofr ) override { AssertSz( fFalse, "NYI!" ); return ErrERRCheck( JET_errNyi ); }
+ ERR ErrFlushFileBuffers( _In_ const IOFLUSHREASON iofr, _In_ const IFileAPI::FileFlushMode ffm ) override { AssertSz( fFalse, "NYI!" ); return ErrERRCheck( JET_errNyi ); }
void SetNoFlushNeeded() override { AssertSz( fFalse, "NYI!" ); }
ERR ErrIOSize( DWORD* const pcbSize ) override { AssertSz( fFalse, "NYI!" ); return ErrERRCheck( JET_errNyi ); }
ERR ErrSectorSize( DWORD* const pcbSize ) override { AssertSz( fFalse, "NYI!" ); return ErrERRCheck( JET_errNyi ); }
diff --git a/dev/ese/published/inc/os/memory.hxx b/dev/ese/published/inc/os/memory.hxx
index 8fd63660..6fbf4781 100644
--- a/dev/ese/published/inc/os/memory.hxx
+++ b/dev/ese/published/inc/os/memory.hxx
@@ -252,10 +252,12 @@ extern INT g_fMemCheck;
#ifdef MEM_CHECK
-INLINE const CHAR * const SzNewFile();
-INLINE ULONG UlNewLine();
+const CHAR * const SzNewFile();
+ULONG UlNewLine();
#endif
+#ifdef OS_LAYER_USE_NEW_OVERRIDE
+
_Ret_maybenull_ _Post_writable_byte_size_(cbSize)
INLINE void* __cdecl operator new( const size_t cbSize )
{
@@ -290,6 +292,7 @@ inline void* __cdecl operator new[](size_t size) { return operator new(size); }
inline void __cdecl operator delete[](void* p) { operator delete(p); }
#pragma pop_macro("new")
+#endif // OS_LAYER_USE_NEW_OVERRIDE
// Page Memory Control
diff --git a/dev/ese/published/inc/os/osblockcache.hxx b/dev/ese/published/inc/os/osblockcache.hxx
index d70ddaf0..137a627d 100644
--- a/dev/ese/published/inc/os/osblockcache.hxx
+++ b/dev/ese/published/inc/os/osblockcache.hxx
@@ -155,7 +155,9 @@ class IFileFilter // ff
// Flushes all data previously written for the current file.
- virtual ERR ErrFlush( _In_ const IOFLUSHREASON iofr, _In_ const IFileFilter::IOMode iom ) = 0;
+ virtual ERR ErrFlush( _In_ const IOFLUSHREASON iofr,
+ _In_ const IFileAPI::FileFlushMode ffm,
+ _In_ const IFileFilter::IOMode iom ) = 0;
};
constexpr IFileFilter::IOMode iomRaw = IFileFilter::IOMode::iomRaw;
@@ -757,13 +759,15 @@ INLINE BOOL operator>=( _In_ const TouchNumber tonoA, _In_ const TouchNumber ton
enum class UpdateNumber : USHORT // updno
{
updnoInvalid = 0,
+ updnoFirst = 1,
updnoMax = 65535,
};
constexpr UpdateNumber updnoInvalid = UpdateNumber::updnoInvalid;
+constexpr UpdateNumber updnoFirst = UpdateNumber::updnoFirst;
constexpr UpdateNumber updnoMax = UpdateNumber::updnoMax;
-INLINE UpdateNumber operator+( _In_ const UpdateNumber updno, _In_ const LONG i ) { return ( (LONG)updno + i > (LONG)updnoMax ) ? (UpdateNumber)( (LONG)updnoInvalid + 1 ) : (UpdateNumber)( (LONG)updno + i ); }
+INLINE UpdateNumber operator+( _In_ const UpdateNumber updno, _In_ const LONG i ) { return ( (LONG)updno + i > (LONG)updnoMax ) ? (UpdateNumber)( (LONG)updnoFirst + 1 ) : (UpdateNumber)( (LONG)updno + i ); }
INLINE int CmpUpdno( _In_ const UpdateNumber updnoA, _In_ const UpdateNumber updnoB ) { return (SHORT)( (USHORT)updnoA - (USHORT)updnoB ); }
INLINE BOOL operator<( _In_ const UpdateNumber updnoA, _In_ const UpdateNumber updnoB ) { return CmpUpdno( updnoA, updnoB ) < 0; }
INLINE BOOL operator<=( _In_ const UpdateNumber updnoA, _In_ const UpdateNumber updnoB ) { return CmpUpdno( updnoA, updnoB ) <= 0; }
@@ -809,6 +813,7 @@ class CCachedBlock // cbl
BOOL FDirty() const { return m_fDirty != 0; }
BOOL FEverDirty() const { return m_fEverDirty != 0; }
BOOL FPurged() const { return m_fPurged != 0; }
+ UpdateNumber Updno() const { return m_le_updno; }
protected:
@@ -846,7 +851,6 @@ class CCachedBlock // cbl
DWORD DwECC() const { return m_le_dwECC; }
TouchNumber Tono0() const { return m_le_rgtono[ 0 ]; }
TouchNumber Tono1() const { return m_le_rgtono[ 1 ]; }
- UpdateNumber Updno() const { return m_le_updno; }
BYTE RgbitReserved0() const { return m_rgbitReserved0; }
@@ -944,6 +948,11 @@ class CCachedBlockSlot : public CCachedBlock
{
}
+ CCachedBlockSlot( _In_ const CCachedBlockSlot& other )
+ {
+ memcpy( this, &other, sizeof( *this ) );
+ }
+
QWORD IbSlab() const { return m_le_ibSlab; }
ChunkNumber Chno() const { return m_le_chno; }
SlotNumber Slno() const { return m_le_slno; }
@@ -1015,7 +1024,7 @@ class CCachedBlockSlotState : public CCachedBlockSlot
BOOL FSlotUpdated() const { return m_fSlotUpdated; }
BOOL FClusterUpdated() const { return m_fClusterUpdated; }
BOOL FSuperceded() const { return m_fSuperceded; }
- BOOL FFirstUpdate() const { return Updno() == (UpdateNumber)1; }
+ BOOL FFirstUpdate() const { return Updno() == updnoFirst; }
static void Dump( _In_ const CCachedBlockSlotState& slotst,
_In_ CPRINTF* const pcprintf,
@@ -1240,6 +1249,10 @@ class ICachedBlockSlab // cbs
virtual BOOL FDirty() = 0;
+ // Indicates the number of invalid slots in the slab.
+
+ virtual int CInvalidSlot() = 0;
+
// Callback used to indicate that a slab is saved.
typedef void (*PfnSlabSaved)( _In_ const ERR err,
@@ -1447,6 +1460,8 @@ class IBlockCacheFactory // bcf
virtual ERR ErrDetachFile( _In_z_ const WCHAR* const wszFilePath,
_In_opt_ const IBlockCacheFactory::PfnDetachFileStatus pfnDetachFileStatus,
_In_opt_ const DWORD_PTR keyDetachFileStatus ) = 0;
+
+ virtual ERR ErrIsCachedFile( _In_z_ const WCHAR* const wszFilePath, _Out_ BOOL* const pfCached ) = 0;
};
class COSBlockCacheFactory
diff --git a/dev/ese/published/inc/os/oseventtrace.g.hxx b/dev/ese/published/inc/os/oseventtrace.g.hxx
index 5c7cf772..92f490b7 100644
--- a/dev/ese/published/inc/os/oseventtrace.g.hxx
+++ b/dev/ese/published/inc/os/oseventtrace.g.hxx
@@ -90,3 +90,27 @@ enum OSEventTraceGUID
etguidOsTraceBase // general tags autogen'd before this one
};
+enum OSEventTraceKeywordGUID : ULONGLONG
+{
+ _etguidKeywordError = 0x0000000000000001,
+ _etguidKeywordPerformance = 0x0000000000000002,
+ _etguidKeywordTrace = 0x0000000000000004,
+ _etguidKeywordTransaction = 0x0000000000000008,
+ _etguidKeywordSpace = 0x0000000000000010,
+ _etguidKeywordBF = 0x0000000000000020,
+ _etguidKeywordIO = 0x0000000000000040,
+ _etguidKeywordLOG = 0x0000000000000080,
+ _etguidKeywordTask = 0x0000000000000100,
+ _etguidKeywordTest = 0x0000000000000200,
+ _etguidKeywordBFRESMGR = 0x0000000000000400,
+ _etguidKeywordStationId = 0x0000000000000800,
+ _etguidKeywordJETTraceTag = 0x0000000000001000,
+ _etguidKeywordStallLatencies = 0x0000000000002000,
+ _etguidKeywordDataWorkingSet = 0x0000000000004000,
+ _etguidKeywordIOEX = 0x0000000000008000,
+ _etguidKeywordIOSESS = 0x0000000000010000,
+ _etguidKeywordSubstrateTelemetry = 0x0000000000020000,
+ _etguidKeywordBFRESMGRSUBSAMPLED = 0x0000000000040000,
+ _etguidKeywordCompressExp = 0x0000000100000000,
+};
+
diff --git a/dev/ese/published/inc/os/oseventtrace.hxx b/dev/ese/published/inc/os/oseventtrace.hxx
index 89d37af3..3ba0cab2 100644
--- a/dev/ese/published/inc/os/oseventtrace.hxx
+++ b/dev/ese/published/inc/os/oseventtrace.hxx
@@ -23,6 +23,11 @@ INLINE BOOL FOSEventTraceEnabled();
#define OSEventTrace if ( FOSEventTraceEnabled() ) OSEventTrace_
+template< OSEventTraceKeywordGUID etguid >
+INLINE BOOL FOSEventTraceKeywordEnabled();
+
+INLINE BOOL FOSEventTraceAnyKeywordEnabled( const ULONGLONG ullKeywordMask );
+
// The first 8 are generic reasons, resused per event, the next 248 are for whatever
enum TraceStationIdentificationReason : BYTE // tsidr
@@ -137,5 +142,8 @@ template INLINE BOOL COSEventTraceIdCheck::FAnnounceTime< _etguidSysStationId >(
template INLINE BOOL COSEventTraceIdCheck::FAnnounceTime< _etguidIsamDbfilehdrInfo >( const TraceStationIdentificationReason tsidr );
template INLINE BOOL COSEventTraceIdCheck::FAnnounceTime< _etguidFmpStationId >( const TraceStationIdentificationReason tsidr );
+// Used to down sample the cache trace if only the keyword BFRESMGRSUBSAMPLED is set.
+template INLINE BOOL FOSEventTraceKeywordEnabled< _etguidKeywordBFRESMGRSUBSAMPLED >();
+
#endif // _OS_EVENT_TRACE_HXX_INCLUDED
diff --git a/dev/ese/published/inc/os/osfileapi.hxx b/dev/ese/published/inc/os/osfileapi.hxx
index ff640105..63fce7cc 100644
--- a/dev/ese/published/inc/os/osfileapi.hxx
+++ b/dev/ese/published/inc/os/osfileapi.hxx
@@ -357,7 +357,29 @@ class IFileAPI // fapi
_Out_ QWORD* const pibStartTrimmedRegion,
_Out_ QWORD* const pcbTrimmed ) = 0;
- virtual ERR ErrFlushFileBuffers( const IOFLUSHREASON iofr ) = 0;
+ // Flush
+
+ // Flags indicating the portion of a file's metadata and/or data to flush.
+
+ enum class FileFlushMode // ffm
+ {
+ ffmAll = 0, // Flush the file's metadata and data.
+ ffmDataOnly = 1, // Flush the file's data only.
+ };
+
+ // Synchronously flushes the requested portion of the file's metadata and/or data.
+
+ virtual ERR ErrFlushFileBuffers( _In_ const IOFLUSHREASON iofr,
+ _In_ const IFileAPI::FileFlushMode ffm = IFileAPI::FileFlushMode::ffmAll ) = 0;
+
+ // Returns the number of Write IOs that are unflushed or flush pending
+ // since the last ErrFlushFileBuffers call.
+
+ virtual LONG64 CioNonFlushed() const = 0;
+
+ // Indicates that a flush is not required for any Write IOs that are unflushed or
+ // flush pending since the last ErrFlushFileBuffers call.
+
virtual void SetNoFlushNeeded() = 0;
// I/O
@@ -377,6 +399,8 @@ class IFileAPI // fapi
// to later surface a PfnIOComplete. If the ErrIORead / ErrIOWrite
// functions are going to return a quota exceeded / errDiskTilt error,
// this function will not be called.
+ //
+ // NOTE: pvIOContext is only provided for async I/O.
typedef void (*PfnIOHandoff)( const ERR err,
IFileAPI* const pfapi,
@@ -515,11 +539,6 @@ class IFileAPI // fapi
virtual ERR ErrDiskId( ULONG_PTR* const pulDiskId ) const = 0;
- // get number of Write IOs that are unflushed or flush pending
- // since last ErrFlushFileBuffers call
-
- virtual LONG64 CioNonFlushed() const = 0;
-
// get seek penalty (in order to identify SSD)
virtual BOOL FSeekPenalty() const = 0;
@@ -536,6 +555,10 @@ class IFileAPI // fapi
DEFINE_ENUM_FLAG_OPERATORS_BASIC( IFileAPI::FileModeFlags )
+constexpr IFileAPI::FileFlushMode ffmAll = IFileAPI::FileFlushMode::ffmAll;
+constexpr IFileAPI::FileFlushMode ffmDataOnly = IFileAPI::FileFlushMode::ffmDataOnly;
+
+
// Exposing for log zero filling
extern QWORD g_cbZero;
extern BYTE* g_rgbZero;
diff --git a/dev/ese/published/inc/os/string.hxx b/dev/ese/published/inc/os/string.hxx
index e6d2a6b7..90abf952 100644
--- a/dev/ese/published/inc/os/string.hxx
+++ b/dev/ese/published/inc/os/string.hxx
@@ -8,109 +8,139 @@
// string with the singular exception of being passed a buffer that has zero length.
#include
-#ifndef PSTR
-typedef _Null_terminated_ char * PSTR; /* ASCII string (char *) null terminated */
-#ifndef PCSTR
-#endif
-typedef _Null_terminated_ const char * PCSTR; /* const ASCII string (char *) null terminated */
-#ifndef PWSTR
-#endif
-typedef _Null_terminated_ wchar_t * PWSTR; /* Unicode string (char *) null terminated */
-#ifndef PCWSTR
-#endif
-typedef _Null_terminated_ const wchar_t * PCWSTR; /* const Unicode string (char *) null terminated */
-#endif
#undef STRSAFE_NO_DEPRECATE
-#ifndef _HRESULT_DEFINED
-#define _HRESULT_DEFINED
-typedef _Return_type_success_(return >= 0) LONG HRESULT; // required b/c we define/use the StringXxxXxxx() functions inline ...
-#endif // _HRESULT_DEFINED
-
-#pragma prefast(push)
-#pragma prefast(disable:28196, "Do not bother us with strsafe, someone else owns that.")
-#pragma prefast(disable:28205, "Do not bother us with strsafe, someone else owns that.")
-#include "strsafe.h"
-#pragma prefast(pop)
-
#include
-// get the length of the string
-ERR ErrFromStrsafeHr ( HRESULT hr );
-
-LONG LOSStrLengthA( _In_ PCSTR const sz );
-LONG LOSStrLengthW( _In_ PCWSTR const wsz );
-LONG LOSStrLengthUnalignedW( _In_ const UnalignedLittleEndian< WCHAR > * wsz );
-LONG LOSStrLengthMW( _In_ PCWSTR const wsz );
-
-// copy a string
-
-#define ErrOSStrCbCopyA( szDst, cbDst, szSrc) ErrFromStrsafeHr( StringCbCopyA( szDst, cbDst, szSrc) )
-#define ErrOSStrCbCopyW( wszDst, cbDst, wszSrc) ErrFromStrsafeHr( StringCbCopyW( wszDst, cbDst, wszSrc) )
-#if DBG
-#define OSStrCbCopyA( szDst, cbDst, szSrc ) { if(ErrOSStrCbCopyA( szDst, cbDst, szSrc )){ AssertSz( fFalse, "Success expected"); } }
-#define OSStrCbCopyW( wszDst, cbDst, wszSrc ) { if(ErrOSStrCbCopyW( wszDst, cbDst, wszSrc )){ AssertSz( fFalse, "Success expected"); } }
-#else
-#define OSStrCbCopyA( szDst, cbDst, szSrc ) ErrOSStrCbCopyA( szDst, cbDst, szSrc )
-#define OSStrCbCopyW( wszDst, cbDst, wszSrc ) ErrOSStrCbCopyW( wszDst, cbDst, wszSrc )
-#endif
+//
+// get the length of the string in characters.
+// Note the unusual usage. Most of our string handling uses count of bytes.
+// Historically, however, string length is returned as count of characters.
+LONG LOSStrLengthA(
+ _In_ PCSTR const sz,
+ _In_ ULONG cchMax = ulMax );
+LONG LOSStrLengthW(
+ _In_ PCWSTR const wsz,
+ _In_ ULONG cchMax = ulMax );
+LONG LOSStrLengthUnalignedW(
+ _In_ const UnalignedLittleEndian< WCHAR > * wsz,
+ _In_ ULONG cchMax = ulMax );
+LONG LOSStrLengthMW(
+ _In_ PCWSTR const wsz );
+
+//
+// copy a string up to a maximum byte count.
+ERR ErrOSStrCbCopyA(
+ _In_ PSTR szDst,
+ _In_ SIZE_T cbDst,
+ _In_ PCSTR szSrc );
+ERR ErrOSStrCbCopyW(
+ _In_ PWSTR szDst,
+ _In_ SIZE_T cbDst,
+ _In_ PCWSTR szSrc );
+#define OSStrCbCopyA( szDst, cbDst, szSrc ) \
+ { if(ErrOSStrCbCopyA( szDst, cbDst, szSrc )){ AssertSz( fFalse, "Success expected"); } }
+#define OSStrCbCopyW( wszDst, cbDst, wszSrc ) \
+ { if(ErrOSStrCbCopyW( wszDst, cbDst, wszSrc )){ AssertSz( fFalse, "Success expected"); } }
// append a string
-
-#define ErrOSStrCbAppendA( szDst, cbDst, szSrc ) ErrFromStrsafeHr( StringCbCatA( szDst, cbDst, szSrc ) )
-#define ErrOSStrCbAppendW( wszDst, cbDst, wszSrc ) ErrFromStrsafeHr( StringCbCatW( wszDst, cbDst, wszSrc ) )
-#if DBG
-#define OSStrCbAppendA( szDst, cbDst, szSrc ) { if(ErrOSStrCbAppendA( szDst, cbDst, szSrc )){ AssertSz( fFalse, "Success expected"); } }
-#define OSStrCbAppendW( wszDst, cbDst, wszSrc ) { if(ErrOSStrCbAppendW( wszDst, cbDst, wszSrc )){ AssertSz( fFalse, "Success expected"); } }
-#else
-#define OSStrCbAppendA( szDst, cbDst, szSrc ) ErrOSStrCbAppendA( szDst, cbDst, szSrc )
-#define OSStrCbAppendW( wszDst, cbDst, wszSrc ) ErrOSStrCbAppendW( wszDst, cbDst, wszSrc )
-#endif
-
+ERR ErrOSStrCbAppendA(
+ _In_ PSTR szDst,
+ _In_ SIZE_T cbDst,
+ _In_ PCSTR szSrc );
+ERR ErrOSStrCbAppendW(
+ _In_ PWSTR wszDst,
+ _In_ SIZE_T cbDst,
+ _In_ PCWSTR wszSrc );
+#define OSStrCbAppendA( szDst, cbDst, szSrc ) \
+ { if( ErrOSStrCbAppendA( szDst, cbDst, szSrc ) ){ AssertSz( fFalse, "Success expected"); } }
+#define OSStrCbAppendW( wszDst, cbDst, wszSrc ) \
+ { if( ErrOSStrCbAppendW( wszDst, cbDst, wszSrc ) ){ AssertSz( fFalse, "Success expected"); } }
+
+//
// compare the strings (up to the given maximum length). if the first string
// is "less than" the second string, -1 is returned. if the strings are "equal",
// 0 is returned. if the first string is "greater than" the second string, +1 is returned.
-
-LONG LOSStrCompareA( _In_ PCSTR const pszStr1, _In_ PCSTR const pszStr2, _In_ const ULONG cchMax = ~ULONG( 0 ) );
-LONG LOSStrCompareW( _In_ PCWSTR const pwszStr1, _In_ PCWSTR const pwszStr2, _In_ const ULONG cchMax = ~ULONG( 0 ) );
-
-
-// create a formatted string in a given buffer
-
-void __cdecl OSStrCbVFormatA ( __out_bcount(cbBuffer) PSTR szBuffer, size_t cbBuffer, __format_string PCSTR szFormat, va_list alist );
-void __cdecl OSStrCbFormatA ( __out_bcount(cbBuffer) PSTR szBuffer, size_t cbBuffer, __format_string PCSTR szFormat, ...);
-void __cdecl OSStrCbFormatW ( __out_bcount(cbBuffer) PWSTR szBuffer, size_t cbBuffer, __format_string PCWSTR szFormat, ...);
-ERR __cdecl ErrOSStrCbFormatA ( __out_bcount(cbBuffer) PSTR szBuffer, size_t cbBuffer, __format_string PCSTR szFormat, ...);
-ERR __cdecl ErrOSStrCbFormatW ( __out_bcount(cbBuffer) PWSTR szBuffer, size_t cbBuffer, __format_string PCWSTR szFormat, ...);
-
-// Formats a GUID in a given given buffer.
-// Note: Does not exist. If it's necessary, please use/refactor WszCATFormatSortID()
-// ERR ErrOSStrCbFormatGuid( _Out_writes_bytes_(37*2) PWSTR szBuffer, _In_ const GUID* pguid );
-
+// Note the unusual usage. Most of our string handling uses count of bytes.
+// Historically, however, string length is returned as count of characters.
+LONG LOSStrCompareA(
+ _In_ PCSTR const pszStr1,
+ _In_ PCSTR const pszStr2,
+ _In_ const ULONG cchMax = -1 );
+LONG LOSStrCompareW(
+ _In_ PCWSTR const pwszStr1,
+ _In_ PCWSTR const pwszStr2,
+ _In_ const ULONG cchMax = -1 );
+
+//
+// create a formatted string in a given buffer and a va_list
+ERR __cdecl ErrOSStrCbVFormatA(
+ _Out_writes_bytes_(cbBuffer) PSTR szBuffer,
+ SIZE_T cbBuffer,
+ _Printf_format_string_ PCSTR szFormat,
+ va_list alist );
+ERR __cdecl ErrOSStrCbVFormatW(
+ _Out_writes_bytes_(cbBuffer) PWSTR szBuffer,
+ SIZE_T cbBuffer,
+ _Printf_format_string_ PCWSTR szFormat,
+ va_list alist );
+#define OSStrCbVFormatA( szBuffer, cbBuffer, szFormat, alist) \
+ { if ( ErrOSStrCbVFormatA( szBuffer, cbBuffer, szFormat, alist ) ){ AssertSz( fFalse, "Success expected" ); } }
+#define OSStrCbVFormatW( szBuffer, cbBuffer, szFormat, alist) \
+ { if ( ErrOSStrCbVFormatW( szBuffer, cbBuffer, szFormat, alist ) ){ AssertSz( fFalse, "Success expected" ); } }
+
+//
+// create a formatted string in a given buffer with a variadac parameter list
+ERR __cdecl ErrOSStrCbFormatA(
+ _Out_writes_bytes_(cbBuffer) PSTR szBuffer,
+ SIZE_T cbBuffer,
+ _Printf_format_string_ PCSTR szFormat,
+ ...);
+ERR __cdecl ErrOSStrCbFormatW (
+ _Out_writes_bytes_(cbBuffer) PWSTR szBuffer,
+ SIZE_T cbBuffer,
+ _Printf_format_string_ PCWSTR szFormat,
+ ...);
+#define OSStrCbFormatA( szBuffer, cbBuffer, szFormat, ... ) \
+ { if ( ErrOSStrCbFormatA( szBuffer, cbBuffer, szFormat, __VA_ARGS__ ) ){ AssertSz( fFalse, "Success expected" ); } }
+#define OSStrCbFormatW( szBuffer, cbBuffer, szFormat, ... ) \
+ { if ( ErrOSStrCbFormatW( szBuffer, cbBuffer, szFormat, __VA_ARGS__ ) ){ AssertSz( fFalse, "Success expected" ); } }
+
+//
// returns a pointer to the next character in the string. when no more
// characters are left, the given ptr is returned.
-
-VOID OSStrCharFindA( _In_ PCSTR const szStr, const char ch, _Outptr_result_maybenull_ PSTR * const pszFound );
-VOID OSStrCharFindW( _In_ PCWSTR const wszStr, const wchar_t wch, _Outptr_result_maybenull_ PWSTR * const pwszFound );
+VOID OSStrCharFindA(
+ _In_ PCSTR const szStr,
+ const CHAR ch,
+ _Outptr_result_maybenull_ PSTR * const pszFound );
+VOID OSStrCharFindW(
+ _In_ PCWSTR const wszStr,
+ const WCHAR wch,
+ _Outptr_result_maybenull_ PWSTR * const pwszFound );
// find the last occurrence of the given character in the given string and
// return a pointer to that character. NULL is returned when the character
// is not found.
-
-VOID OSStrCharFindReverseA( _In_ PCSTR const szStr, const char ch, _Outptr_result_maybenull_ PSTR * const pszFound );
-VOID OSStrCharFindReverseW( _In_ PCWSTR const wszStr, const wchar_t wch, _Outptr_result_maybenull_ PWSTR * const pwszFound );
+VOID OSStrCharFindReverseA(
+ _In_ PCSTR const szStr,
+ const CHAR ch,
+ _Outptr_result_maybenull_ PSTR * const pszFound );
+VOID OSStrCharFindReverseW(
+ _In_ PCWSTR const wszStr,
+ const WCHAR wch,
+ _Outptr_result_maybenull_ PWSTR * const pwszFound );
+//
// check for a trailing path-delimeter
-
BOOL FOSSTRTrailingPathDelimiterA( _In_ PCSTR const pszPath );
BOOL FOSSTRTrailingPathDelimiterW( _In_ PCWSTR const pwszPath );
+//
// convert with a fixed conversion code page (1252 / Windows English) or use a context dependant
// conversion (CP_ACP).
-
typedef enum
{
// Should be used when the same conversion should be used
@@ -118,66 +148,56 @@ typedef enum
// should only be in ASCII).
OSSTR_FIXED_CONVERSION = 0,
+
// Should be used when the OS locale and setting should be
// considered (e.g.: customer data).
OSSTR_CONTEXT_DEPENDENT_CONVERSION = 1,
-} OSSTR_CONVERSION;
-// convert a byte string to a wide-char string
+} OSSTR_CONVERSION;
-ERR ErrOSSTRAsciiToUnicode( _In_ PCSTR const pszIn,
- _Out_opt_z_cap_post_count_(cwchOut, *pcwchRequired) PWSTR const pwszOut,
- const size_t cwchOut,
- size_t * const pcwchRequired = NULL,
- const OSSTR_CONVERSION osstrConversion = OSSTR_CONTEXT_DEPENDENT_CONVERSION );
+typedef enum
+{
+ OSSTR_NOT_LOSSY = 0,
+ OSSTR_ALLOW_LOSSY = 1
+} OSSTR_LOSSY;
+//
+// convert a byte string to a wide-char string
+ERR ErrOSSTRAsciiToUnicode(
+ _In_ PCSTR const pszIn,
+ _Out_opt_z_cap_post_count_(cwchOut, *pcwchRequired) PWSTR const pwszOut,
+ const SIZE_T cwchOut,
+ SIZE_T * const pcwchRequired = NULL,
+ const OSSTR_CONVERSION osstrConversion = OSSTR_CONTEXT_DEPENDENT_CONVERSION
+ );
+
+//
// convert a wide-char string to a byte string
-typedef enum { OSSTR_NOT_LOSSY = 0, OSSTR_ALLOW_LOSSY = 1 } OSSTR_LOSSY;
-
-ERR ErrOSSTRUnicodeToAscii( _In_ PCWSTR const pwszIn,
- _Out_opt_z_cap_post_count_(cchOut, *pcchRequired) PSTR const pwszOut,
- const size_t cchOut,
- size_t * const pcchRequired = NULL,
- const OSSTR_LOSSY fLossy = OSSTR_NOT_LOSSY,
- const OSSTR_CONVERSION osstrConversion = OSSTR_CONTEXT_DEPENDENT_CONVERSION );
-
-#ifdef __TCHAR_DEFINED
-// convert a WCHAR string to a _TCHAR string
-
-ERR ErrOSSTRUnicodeToTchar( const wchar_t *const pwszIn,
- __out_ecount(ctchOut) _TCHAR *const ptszOut,
- const INT ctchOut,
- const OSSTR_CONVERSION osstrConversion = OSSTR_CONTEXT_DEPENDENT_CONVERSION );
-#endif
-
-// generic names for UNICODE and non-UNICODE cases
-
-#ifdef UNICODE
-
-#define LOSStrLength LOSStrLengthW
-#define OSStrAppend OSSTRAppendW
-#define LOSSTRCompare LOSSTRCompareW
-// #define OSStrFormat OSStrFormatW
-//#define OSStrCharFind OSStrCharFindW
-//#define OSStrCharFindReverse OSStrCharFindReverseW
-#define FOSSTRTrailingPathDelimiter FOSSTRTrailingPathDelimiterW
-
-#else // !UNICODE
-
-#define LOSStrLength LOSStrLengthA
-#define OSStrAppend OSSTRAppendA
-#define LOSSTRCompare LOSSTRCompareA
-//#define OSStrFormat OSStrFormatA
-//#define OSStrCharFind OSStrCharFindA
-//#define OSStrCharFindReverse OSStrCharFindReverseA
-#define FOSSTRTrailingPathDelimiter FOSSTRTrailingPathDelimiterA
-
-#endif // UNICODE
-
-
-ERR ErrOSSTRAsciiToUnicodeM( _In_ PCSTR const szzMultiIn, __out_ecount_z(cchMax) WCHAR * wszNew, ULONG cchMax, size_t * const pcchActual, const OSSTR_CONVERSION osstrConversion = OSSTR_CONTEXT_DEPENDENT_CONVERSION );
-ERR ErrOSSTRUnicodeToAsciiM( _In_ PCWSTR const wszzMultiIn, __out_ecount_z(cchMax) char * szNew, ULONG cchMax, size_t * const pcchActual, const OSSTR_CONVERSION osstrConversion = OSSTR_CONTEXT_DEPENDENT_CONVERSION );
+ERR ErrOSSTRUnicodeToAscii(
+ _In_ PCWSTR const pwszIn,
+ _Out_opt_z_cap_post_count_(cchOut, *pcchRequired) PSTR const pwszOut,
+ const SIZE_T cchOut,
+ SIZE_T * const pcchRequired = NULL,
+ const OSSTR_LOSSY fLossy = OSSTR_NOT_LOSSY,
+ const OSSTR_CONVERSION osstrConversion = OSSTR_CONTEXT_DEPENDENT_CONVERSION
+ );
+
+ERR ErrOSSTRAsciiToUnicodeM(
+ _In_ PCSTR const szzMultiIn,
+ __out_ecount_z(cchMax) WCHAR * wszNew,
+ ULONG cchMax,
+ SIZE_T * const pcchActual,
+ const OSSTR_CONVERSION osstrConversion = OSSTR_CONTEXT_DEPENDENT_CONVERSION
+ );
+
+ERR ErrOSSTRUnicodeToAsciiM(
+ _In_ PCWSTR const wszzMultiIn,
+ __out_ecount_z(cchMax) CHAR * szNew,
+ ULONG cchMax,
+ SIZE_T * const pcchActual,
+ const OSSTR_CONVERSION osstrConversion = OSSTR_CONTEXT_DEPENDENT_CONVERSION
+ );
#endif // __OS_STRING_HXX_INCLUDED
diff --git a/dev/ese/published/inc/os/thread.hxx b/dev/ese/published/inc/os/thread.hxx
index 1e28587d..1d4ab6df 100644
--- a/dev/ese/published/inc/os/thread.hxx
+++ b/dev/ese/published/inc/os/thread.hxx
@@ -42,9 +42,16 @@ enum EThreadPriority
// creates a thread with the specified attributes
-const ERR ErrUtilThreadICreate( const PUTIL_THREAD_PROC pfnStart, const DWORD cbStack, const EThreadPriority priority, THREAD* const pThread, const DWORD_PTR dwParam, const _TCHAR* const szStart );
+const ERR ErrUtilThreadICreate(
+ const PUTIL_THREAD_PROC pfnStart,
+ const DWORD cbStack,
+ const EThreadPriority priority,
+ THREAD* const pThread,
+ const DWORD_PTR dwParam,
+ const CHAR* const szStart );
+
#define ErrUtilThreadCreate( pfnStart, cbStack, priority, phThread, dwParam ) \
- ( ErrUtilThreadICreate( pfnStart, cbStack, priority, phThread, dwParam, _T( #pfnStart ) ) )
+ ( ErrUtilThreadICreate( pfnStart, cbStack, priority, phThread, dwParam, #pfnStart ) )
// waits for the specified thread to exit and returns its return value
diff --git a/dev/ese/published/inc/os/time.hxx b/dev/ese/published/inc/os/time.hxx
index 029aa653..196be7e2 100644
--- a/dev/ese/published/inc/os/time.hxx
+++ b/dev/ese/published/inc/os/time.hxx
@@ -33,6 +33,10 @@ void OSTimeSetTimeInjection( const DWORD eTimeInjNegWrapMode, const TICK dtickTi
TICK TickOSTimeCurrent();
+// returns the current timer tick count (1000 Hz) factoring out time the computer was hibernating or asleep
+
+TICK TickOSTimeInterruptCurrent();
+
// performs an overflow aware comparison of two absolute tick counts
INLINE LONG TickCmp( TICK tick1, TICK tick2 )
diff --git a/dev/ese/published/inc/os/trace.hxx b/dev/ese/published/inc/os/trace.hxx
index 748f7dfe..9cdc6b25 100644
--- a/dev/ese/published/inc/os/trace.hxx
+++ b/dev/ese/published/inc/os/trace.hxx
@@ -6,6 +6,8 @@
// Required for std::move()
#include
+// Required for wprintf
+#include
class TRACEINFO
{
diff --git a/dev/ese/published/inc/os/types.hxx b/dev/ese/published/inc/os/types.hxx
index 3193ced6..5deb3d89 100644
--- a/dev/ese/published/inc/os/types.hxx
+++ b/dev/ese/published/inc/os/types.hxx
@@ -6,6 +6,7 @@
#include
#include
+#include
// build options
@@ -14,6 +15,11 @@
#define INLINE inline
#define NOINLINE __declspec(noinline)
+// Required to prevent MSVC from adding extra bytes in class layout when using multiple empty base classes.
+// Note: this is the default behavior on other compilers.
+// Used primarily by Unaligned Little/BigEndian template classes.
+#define EMPTY_BASES __declspec(empty_bases)
+
#define PUBLIC extern
#define LOCAL_BROKEN
#define LOCAL static
@@ -130,8 +136,6 @@ typedef DWORD LCID;
typedef GUID SORTID;
#define SORTIDNil { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }
-typedef wchar_t WCHAR;
-
typedef struct
{
INT month;
@@ -294,7 +298,7 @@ inline T1& operator>>=( T1& t1, const T2& t2 )
// host endian-ness
-const BOOL fHostIsLittleEndian = fTrue;
+constexpr BOOL fHostIsLittleEndian = fTrue;
inline constexpr BOOL FHostIsLittleEndian()
{
return fHostIsLittleEndian;
@@ -421,18 +425,6 @@ inline unsigned __int32 ReverseBytes< unsigned __int32 >( const unsigned __int32
return ReverseFourBytes( (const unsigned __int32) dw );
}
-template<>
-inline LONG ReverseBytes< LONG >( const LONG dw )
-{
- return ReverseFourBytes( (const unsigned __int32) dw );
-}
-
-template<>
-inline ULONG ReverseBytes< ULONG >( const ULONG dw )
-{
- return ReverseFourBytes( (const unsigned __int32) dw );
-}
-
template<>
inline __int64 ReverseBytes< __int64 >( const __int64 qw )
{
@@ -473,13 +465,13 @@ struct extract_typearg< X >
using TArg = T;
};
-// A base class providing operator overloads for aligned data.
+// A base class providing arithmetic operator overloads for types that handle aligned/unaligned LittlEndian/BigEndian data.
// Requires the use of CRTP pattern to invoke static polymorphism for selecting the right conversion functions.
// Requires the derived class to provide conversion functions to/from an integral type.
//
-// Note that we don't need to worry about whether the data is aligned or not. The line:
+// Note that we don't need to worry about whether the data is aligned or not, little or big endian. The line:
// TArg converted = (TArg) static_cast( *this );
-// makes an aligned copy on the stack of the underlying T datatype, regardless of whether
+// makes a platform endian aligned copy on the stack of the underlying T datatype, regardless of whether
// this OperatorOverload template is being used as the base for aligned OR unaligned data.
template
class COperatorOverloads
@@ -557,14 +549,36 @@ public:
};
+// A helper class to create stack copies of aligned and endian-corrected data.
+// Provides pointer semantics on the object to allow calling const functions,
+// if the underlying type is a struct/class.
+template
+struct AlignedPlatformEndian
+{
+ T m_t;
+ const T* operator->() const { return &m_t; }
+};
+
+// Provides struct/class deref operator overload to use with unaligned, endian types encapsulating structs/classes.
+// Works similarly to COperatorOverloads above.
+template
+class DerefOverload
+{
+ using TArg = typename extract_typearg::TArg;
+
+public:
+ auto operator->() const { return AlignedPlatformEndian{ ( TArg ) static_cast( *this ) }; }
+};
+
+
// big endian type template
template< class T >
-class BigEndian : public COperatorOverloads< BigEndian >
+class EMPTY_BASES BigEndian : public COperatorOverloads< BigEndian >, public DerefOverload< BigEndian >
{
public:
- BigEndian< T >() {};
+ BigEndian< T >() = default;
BigEndian< T >( const BigEndian< T >& be_t );
BigEndian< T >( const T& t );
@@ -619,10 +633,10 @@ inline BigEndian< T >& BigEndian< T >::operator=( const T& t )
// little endian type template
template< class T >
-class LittleEndian : public COperatorOverloads< LittleEndian >
+class EMPTY_BASES LittleEndian : public COperatorOverloads< LittleEndian >, public DerefOverload< LittleEndian >
{
public:
- LittleEndian< T >() {};
+ LittleEndian< T >() = default;
LittleEndian< T >( const LittleEndian< T >& le_t );
LittleEndian< T >( const T& t );
@@ -687,10 +701,10 @@ inline LittleEndian< T >& LittleEndian< T >::operator=( const T& t )
#define UCAST(T) *(T PERMIT_UNALIGNED_ACCESS *)
template< class T >
-class Unaligned : public COperatorOverloads< Unaligned >
+class EMPTY_BASES Unaligned : public COperatorOverloads< Unaligned >, public DerefOverload< Unaligned >
{
public:
- Unaligned< T >() PERMIT_UNALIGNED_ACCESS {};
+ Unaligned< T >() PERMIT_UNALIGNED_ACCESS = default;
Unaligned< T >( const Unaligned< T >& u_t ) PERMIT_UNALIGNED_ACCESS;
Unaligned< T >( const T& t ) PERMIT_UNALIGNED_ACCESS;
@@ -744,10 +758,10 @@ inline Unaligned< T >& Unaligned< T >::operator=( const T& t ) PERMIT_UNALIGNED_
// unaligned big endian type template
template< class T >
-class UnalignedBigEndian : public COperatorOverloads< UnalignedBigEndian >
+class EMPTY_BASES UnalignedBigEndian : public COperatorOverloads< UnalignedBigEndian >, public DerefOverload< UnalignedBigEndian >
{
public:
- UnalignedBigEndian< T >() PERMIT_UNALIGNED_ACCESS {};
+ UnalignedBigEndian< T >() PERMIT_UNALIGNED_ACCESS = default;
UnalignedBigEndian< T >( const UnalignedBigEndian< T >& ube_t ) PERMIT_UNALIGNED_ACCESS;
UnalignedBigEndian< T >( const T& t ) PERMIT_UNALIGNED_ACCESS;
@@ -802,10 +816,10 @@ inline UnalignedBigEndian< T >& UnalignedBigEndian< T >::operator=( const T& t )
// unaligned little endian type template
template< class T >
-class UnalignedLittleEndian : public COperatorOverloads< UnalignedLittleEndian >
+class EMPTY_BASES UnalignedLittleEndian : public COperatorOverloads< UnalignedLittleEndian >, public DerefOverload< UnalignedLittleEndian >
{
public:
- UnalignedLittleEndian< T >() PERMIT_UNALIGNED_ACCESS {};
+ UnalignedLittleEndian< T >() PERMIT_UNALIGNED_ACCESS = default;
UnalignedLittleEndian< T >( const UnalignedLittleEndian< T >& ule_t ) PERMIT_UNALIGNED_ACCESS;
UnalignedLittleEndian< T >( const T& t ) PERMIT_UNALIGNED_ACCESS;
@@ -856,6 +870,89 @@ inline UnalignedLittleEndian< T >& UnalignedLittleEndian< T >::operator=( const
return *this;
}
+// Wraps a pointer to UnalignedLittleEndian data.
+// The pointer itself is aligned and platform endian. The data it points to is unaligned little endian.
+// Used to manipulate arrays of unaligned little endian data.
+template
+class UnalignedLittleEndianPtr
+{
+public:
+ // A reference to data pointed by UnalignedLittleEndianPtr
+ // Returned as a result of derefing UnalignedLittleEndianPtr
+ class Ref
+ {
+ public:
+ Ref( T PERMIT_UNALIGNED_ACCESS* ptr ) : m_pT( ptr ) {}
+
+ operator T() const
+ {
+ // Dereference needs unaligned memory access
+ T t = UCAST( T )m_pT;
+ return ReverseBytesOnBE( t );
+ }
+
+ // Asignment operator is marked const because it doesn't modify this object, only modifies referenced data.
+ const Ref& operator=( const T& t ) const
+ {
+ static_assert( !std::is_const::value, "Assignment to a pointer to const is not allowed" );
+ UCAST( T )m_pT = ReverseBytesOnBE( t );
+ return *this;
+ }
+
+ private:
+ T PERMIT_UNALIGNED_ACCESS* m_pT; // this member itself is aligned
+ };
+
+ UnalignedLittleEndianPtr() = default;
+ UnalignedLittleEndianPtr( const UnalignedLittleEndianPtr& ule_t ) { m_pT = ule_t.m_pT; }
+ UnalignedLittleEndianPtr( T PERMIT_UNALIGNED_ACCESS* ptr ) : m_pT( ptr ){}
+
+ Ref operator[]( int index ) { return Ref( m_pT + index ); }
+ Ref operator*() { return Ref( m_pT ); }
+ UnalignedLittleEndianPtr operator+( int index ) const { return UnalignedLittleEndianPtr( m_pT + index ); }
+ bool operator==( const UnalignedLittleEndianPtr& rhs ) const { return m_pT == rhs.m_pT; }
+ bool operator!=( const UnalignedLittleEndianPtr& rhs ) const { return m_pT != rhs.m_pT; }
+
+ T operator[]( int index ) const
+ {
+ T t = UCAST( T )( m_pT + index );
+ return ReverseBytesOnBE( t );
+ }
+
+ T operator*() const
+ {
+ // Dereference operator needs unaligned memory access.
+ T t = UCAST( T )m_pT;
+ return ReverseBytesOnBE( t );
+ }
+
+ UnalignedLittleEndianPtr& operator=( const UnalignedLittleEndianPtr& ule_t )
+ {
+ m_pT = ule_t.m_pT;
+ return *this;
+ }
+
+ UnalignedLittleEndianPtr& operator=( T PERMIT_UNALIGNED_ACCESS* ptr )
+ {
+ m_pT = ptr;
+ return *this;
+ }
+
+ UnalignedLittleEndianPtr& operator++()
+ {
+ ++m_pT;
+ return *this;
+ }
+
+ UnalignedLittleEndianPtr operator++( int )
+ {
+ return UnalignedLittleEndianPtr( m_pT++ );
+ }
+
+private:
+ T PERMIT_UNALIGNED_ACCESS* m_pT; // this member itself is aligned
+};
+
// special type qualifier to allow unaligned access to variables
//
diff --git a/dev/ese/published/inc/sync.hxx b/dev/ese/published/inc/sync.hxx
index 92ddb5fa..b3d8161b 100644
--- a/dev/ese/published/inc/sync.hxx
+++ b/dev/ese/published/inc/sync.hxx
@@ -344,7 +344,7 @@ inline LONG AtomicExchange( LONG* const plTarget, const LONG lValue )
{
OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
- return _InterlockedExchange( plTarget, lValue );
+ return _InterlockedExchange( ( OS_WIN_LONG * )plTarget, lValue );
}
// atomically sets the target to the specified value, returning the target's
@@ -437,7 +437,7 @@ inline LONG AtomicExchangeAdd( LONG * const plTarget, const LONG lValue )
{
OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
- return _InterlockedExchangeAdd( plTarget, lValue );
+ return _InterlockedExchangeAdd( ( OS_WIN_LONG * )plTarget, lValue );
}
// atomically adds the specified value to the target, returning the target's
@@ -460,7 +460,7 @@ inline LONG AtomicCompareExchange( LONG * const plTarget, const LONG lInitial, c
{
OSSYNCAssert( IsAtomicallyModifiable( plTarget ) );
- return _InterlockedCompareExchange( plTarget, lFinal, lInitial );
+ return _InterlockedCompareExchange( ( OS_WIN_LONG * )plTarget, lFinal, lInitial );
}
inline ULONG AtomicCompareExchange( ULONG * const pulTarget, const ULONG ulInitial, const ULONG ulFinal )
diff --git a/dev/ese/src/CMakeLists.txt b/dev/ese/src/CMakeLists.txt
index 34d91c3c..f48a637a 100644
--- a/dev/ese/src/CMakeLists.txt
+++ b/dev/ese/src/CMakeLists.txt
@@ -7,6 +7,7 @@
add_subdirectory(_errstr)
add_subdirectory(_esefile)
add_subdirectory(_etw)
+add_subdirectory(_lz4)
add_subdirectory(_perfctrs)
add_subdirectory(_res)
add_subdirectory(_xpress)
diff --git a/dev/ese/src/_errstr/errdata.txt b/dev/ese/src/_errstr/errdata.txt
index c8e50bef..165a2071 100644
--- a/dev/ese/src/_errstr/errdata.txt
+++ b/dev/ese/src/_errstr/errdata.txt
@@ -95,7 +95,7 @@
INTERNAL_ERR( -332, Unknown, errSPOutOfOwnExtCacheSpace )
INTERNAL_WRN( 333, Unknown, wrnBTMultipageOLC )
EXTERNAL_ERR( -334, Operation, JET_errNTSystemCallFailed ) // eseutil only today
- INTERNAL_WRN( 335, Unknown, wrnBTShallowTree )
+ INTERNAL_ERR( -335, Unknown, errBTShallowTree )
INTERNAL_ERR( -336, Unknown, errBTMergeNotSynchronous )
INTERNAL_WRN( 337, Unknown, wrnSPReservedPages )
EXTERNAL_ERR( -338, Corruption, JET_errBadParentPageLink )
@@ -119,6 +119,13 @@
INTERNAL_WRN( 356, Unknown, wrnSPRequestSpBufRefill )
EXTERNAL_ERR( -357, Corruption, JET_errPageTagCorrupted )
EXTERNAL_ERR( -358, Corruption, JET_errNodeCorrupted )
+ INTERNAL_ERR( -359, State, errBBTBuffFull )
+ INTERNAL_ERR( -360, State, errBBTNodeNotFound )
+ INTERNAL_ERR( -361, State, errBBTCurrencyLost )
+ INTERNAL_WRN( 362, State, wrnBBTMergeTargetFull )
+ INTERNAL_WRN( 363, State, wrnBBTPathUnvisitedNode )
+ EXTERNAL_ERR( -364, Corruption, JET_errBBTNodeCorrupted )
+ EXTERNAL_ERR( -365, Corruption, JET_errBBTBuffCorrupted )
INTERNAL_WRN( 400, Unknown, wrnFLDKeyTooBig )
INTERNAL_ERR( -401, Unknown, errFLDTooManySegments )
INTERNAL_WRN( 402, Unknown, wrnFLDNullKey )
@@ -579,6 +586,7 @@
INTERNAL_ERR( -1946, State, errRBSCorruptUninitializedRBSRemoved )
EXTERNAL_ERR( -1947, Corruption, JET_errRBSRedeleteFDPUnexpected )
EXTERNAL_ERR( -1948, Corruption, JET_errRBSRCPageFDPDeleteFileCorrupt )
+ EXTERNAL_ERR( -1949, Corruption, JET_errRBSRedeleteFDPExpected )
EXTERNAL_WRN( 2000, State, JET_wrnDefragAlreadyRunning )
EXTERNAL_WRN( 2001, State, JET_wrnDefragNotRunning )
EXTERNAL_WRN( 2002, State, JET_wrnDatabaseScanAlreadyRunning )
diff --git a/dev/ese/src/_esefile/esefile.hxx b/dev/ese/src/_esefile/esefile.hxx
index 94214b81..a5ac9320 100644
--- a/dev/ese/src/_esefile/esefile.hxx
+++ b/dev/ese/src/_esefile/esefile.hxx
@@ -7,13 +7,6 @@
#include "cc.hxx"
#include "math.hxx"
-#pragma prefast(push)
-#pragma prefast(disable:26006, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:26007, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28718, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28726, "Dont bother us with tchar, someone else owns that.")
-#include
-#pragma prefast(pop)
#include "os.hxx"
#include "jet.h"
diff --git a/dev/ese/src/_esefile/xsum.cxx b/dev/ese/src/_esefile/xsum.cxx
index 1f495a56..a3b7620a 100644
--- a/dev/ese/src/_esefile/xsum.cxx
+++ b/dev/ese/src/_esefile/xsum.cxx
@@ -102,19 +102,18 @@ static PAGECHECKSUM ChecksumFromPage( const void * const pv, const PAGETYPE page
}
// ================================================================
-static PAGECHECKSUM ComputePageChecksum(
+LOCAL PAGECHECKSUM ComputePageChecksum_(
const void* const pv,
const UINT cb,
const PAGETYPE pagetype,
const ULONG pgno,
- // set fNew to compute new ECC for a page (R/W wrt the large page!!)
- // reset fNew to computer ECC for verification purpose (R/O wrt the page)
- const BOOL fNew = fFalse )
+ const BOOL fNewChecksumFormat,
+ const BOOL fWriteChecksum )
// ================================================================
{
if( FPageHasLongChecksum( pagetype ) )
{
- if( FPageHasNewChecksumFormat( pv, pagetype ) )
+ if( fNewChecksumFormat )
{
// large pages (16/32kiB) always have new checksum format
PAGECHECKSUM pgChecksum;
@@ -131,7 +130,7 @@ static PAGECHECKSUM ComputePageChecksum(
// write checksums into designated location in header block
// so checksum for header block can protect them as well
- if ( fNew )
+ if ( fWriteChecksum )
{
// cast RO ( const void* ) to RW ( PGHDR2* )
PGHDR2* const pPgHdr2 = ( PGHDR2* )pv;
@@ -154,6 +153,18 @@ static PAGECHECKSUM ComputePageChecksum(
return ChecksumOldFormat((unsigned char *)pv, cb);
}
+// ================================================================
+static PAGECHECKSUM ComputePageChecksum(
+ const void* const pv,
+ const UINT cb,
+ const PAGETYPE pagetype,
+ const ULONG pgno,
+ const BOOL fWriteChecksum = fFalse )
+// ================================================================
+{
+ return ComputePageChecksum_( pv, cb, pagetype, pgno, FPageHasNewChecksumFormat( pv, pagetype ), fWriteChecksum );
+}
+
// ================================================================
inline void FlipBit( void * const pv, const INT ibitOffset )
// ================================================================
@@ -215,7 +226,7 @@ static void TryFixPage(
const UINT cblk = fSmallPage ? 1 : cxeChecksumPerPage;
XECHECKSUMERROR rgErr[ cxeChecksumPerPage ] = { xeChecksumNoError, };
- UINT rgibitCorrupted[ cxeChecksumPerPage ] = { IbitNewChecksumFormatFlag( pagetype ), UINT_MAX, UINT_MAX, UINT_MAX, };
+ UINT rgibitCorrupted[ cxeChecksumPerPage ] = { UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, };
UINT ibitCorrupted = UINT_MAX;
// work out correction
@@ -292,9 +303,23 @@ void ChecksumAndPossiblyFixPage(
*pchecksumActual = ComputePageChecksum( pv, cb, pagetype, pgno );
const BOOL fNewChecksumFormat = FPageHasNewChecksumFormat( pv, pagetype );
- if( *pchecksumActual != *pchecksumExpected && fNewChecksumFormat )
+ if ( *pchecksumActual != *pchecksumExpected && *pchecksumExpected != PAGECHECKSUM{ 0 } )
{
- TryFixPage( pv, cb, pagetype, fCorrectError, pfCorrectableError, pibitCorrupted, *pchecksumExpected, *pchecksumActual );
+ // Try correcting bit flips in the page for non-zero pages. (Pages whose checksum isn't 0).
+ // Note that a valid old format checksum can be 0 for some combination of non-zero bits on the page.
+ // A valid new checksum can't be zero because it comprises of two complimentary checksums,
+ // both of which can only be 0 if all of the bits on the page are 0 or 1.
+ // See checksum_amd64.cxx for a detailed description of why that is true.
+
+ // Old checksum format doesn't support error correction.
+ // But it could be that the checksum was new format and the bit that indicated formats got flipped.
+ // Compute the checksum as new format and try fixing it.
+ // If it is fixable, then we know that fNewChecksumFormat bit on the page got flipped.
+ PAGECHECKSUM checksumNewFormat = fNewChecksumFormat ?
+ *pchecksumActual :
+ ComputePageChecksum_( pv, cb, pagetype, pgno, fTrue, fFalse );
+
+ TryFixPage( pv, cb, pagetype, fCorrectError, pfCorrectableError, pibitCorrupted, *pchecksumExpected, checksumNewFormat );
Assert( ( *pfCorrectableError && *pibitCorrupted != -1 ) || ( !*pfCorrectableError && *pibitCorrupted == -1 ) );
// no point in re-computing the checksum if we haven't done any changes
diff --git a/dev/ese/src/_etw/EseEtwEventsPregen.txt b/dev/ese/src/_etw/EseEtwEventsPregen.txt
index cb52cfa7..9d3449a5 100644
--- a/dev/ese/src/_etw/EseEtwEventsPregen.txt
+++ b/dev/ese/src/_etw/EseEtwEventsPregen.txt
@@ -40,11 +40,11 @@ START_TRACE_LIST:
CacheNewPage, 103, win:Informational, "BF Performance DataWorkingSet",
CacheReadPage, 104, win:Informational, "BF Performance DataWorkingSet",
CachePrereadPage, 105, win:Informational, "BF Performance DataWorkingSet",
- CacheWritePage, 106, win:Informational, "BF BFRESMGR Performance DataWorkingSet",
- CacheEvictPage, 107, win:Informational, "BF BFRESMGR DataWorkingSet",
- CacheRequestPage, 108, win:Verbose, "BF BFRESMGR"
- LatchPageDeprecated, 109, win:Informational, "BF BFRESMGR Performance", fDeprecated
- CacheDirtyPage, 110, win:Verbose, "BF BFRESMGR Performance"
+ CacheWritePage, 106, win:Informational, "BF BFRESMGR BFRESMGRSUBSAMPLED Performance DataWorkingSet",
+ CacheEvictPage, 107, win:Informational, "BF BFRESMGR BFRESMGRSUBSAMPLED DataWorkingSet",
+ CacheRequestPage, 108, win:Verbose, "BF BFRESMGR BFRESMGRSUBSAMPLED"
+ LatchPageDeprecated, 109, win:Informational, "BF BFRESMGR BFRESMGRSUBSAMPLED Performance", fDeprecated
+ CacheDirtyPage, 110, win:Verbose, "BF BFRESMGR BFRESMGRSUBSAMPLED Performance"
TransactionBegin, 111, win:Verbose, "Transaction"
TransactionCommit, 112, win:Verbose, "Transaction"
TransactionRollback, 113, win:Verbose, "Transaction"
@@ -80,10 +80,10 @@ START_TRACE_LIST:
CacheScavengeProgress, 143, win:Informational, "BF Performance",
ApiCall_Start, 144, win:Informational, "Performance",
ApiCall_Stop, 145, win:Informational, "Performance", fStopCodeNoTask
- ResMgrInit, 146, win:Informational, "BFRESMGR",
- ResMgrTerm, 147, win:Informational, "BFRESMGR",
- CacheCachePage, 148, win:Verbose, "BF BFRESMGR",
- MarkPageAsSuperCold, 149, win:Verbose, "BF BFRESMGR",
+ ResMgrInit, 146, win:Informational, "BFRESMGR BFRESMGRSUBSAMPLED",
+ ResMgrTerm, 147, win:Informational, "BFRESMGR BFRESMGRSUBSAMPLED",
+ CacheCachePage, 148, win:Verbose, "BF BFRESMGR BFRESMGRSUBSAMPLED",
+ MarkPageAsSuperCold, 149, win:Verbose, "BF BFRESMGR BFRESMGRSUBSAMPLED",
CacheMissLatency, 150, win:Informational, "BF StallLatencies",
BTreePrereadPageRequest, 151, win:Informational, "Performance",
DiskFlushFileBuffers, 152, win:Informational, "IO",
@@ -110,7 +110,7 @@ START_TRACE_LIST:
IOThreadIssueProcessedIO, 173, win:Informational, "IO"
IOIoreqCompletion, 174, win:Informational, "IO StallLatencies"
CacheMemoryUsage, 175, win:Informational, "SubstrateTelemetry"
- CacheSetLgposModify, 176, win:Verbose, "BF BFRESMGR"
+ CacheSetLgposModify, 176, win:Verbose, "BF BFRESMGR BFRESMGRSUBSAMPLED"
START_TRACE_DEFNS:
diff --git a/dev/ese/src/_etw/Microsoft-ETW-ESE.mc b/dev/ese/src/_etw/Microsoft-ETW-ESE.mc
index 1795c94a..ccedf46a 100644
--- a/dev/ese/src/_etw/Microsoft-ETW-ESE.mc
+++ b/dev/ese/src/_etw/Microsoft-ETW-ESE.mc
@@ -107,6 +107,7 @@ ESE_PRE_GEN_BASE_FILE: be pre-processed with eseetw.pl.
http://msdn.microsoft.com/en-us/library/aa382786(VS.85).aspx
-->
+
+
+
/ ){
+ # Line is passed through later
+ $fInKeywordList = 1;
+ }
if ( $szMcLine =~ // ){
print hEtwNewMc $szMcLine;
$fInTaskList = 1;
@@ -466,7 +476,51 @@ sub szpad {
$fInStringList = 1;
}
- if ( $fInTaskList ){
+ if ( $fInKeywordList ){
+
+ if ( $szMcLine =~ /{Name} = -1;
+ $keyword->{Mask} = -1;
+ $fCurrParsingKeyword = 1;
+ }
+
+ elsif ( $szMcLine =~ /\/>/ ){
+ # Keywords should have a mask and a name
+ if ( !$fCurrParsingKeyword ){
+ die "ERROR: Cannot complete the parsing of a keyword without starting it.\n";
+ }
+ if ( $keyword->{Name} == -1 ){
+ die "ERROR: Parsed a keyword without a name in $szEtwBaseMc.\n";
+ }
+ if ( $keyword->{Mask} == -1 ){
+ die "ERROR: Keyword $keyword->{Name} does not have a mask in $szEtwBaseMc.\n";
+ }
+ push @rgsKeywords, $keyword;
+ $fCurrParsingKeyword = 0;
+ }
+
+ elsif ( $szMcLine =~ /mask="0x[0-9]*"\s*$/ ){
+ @MaskParsing = split /\s*"\s*/, $szMcLine;
+ $keyword->{Mask} = @MaskParsing[1];
+ }
+
+ elsif ( $szMcLine =~ /name=".*"\s*$/ ){
+ @NameParsing = split /\s*"\s*/, $szMcLine;
+ $keyword->{Name} = @NameParsing[1];
+ }
+
+ if ( $szMcLine =~ // ){
+ $fInKeywordList = 0;
+ }
+
+ # pass the $line through unaltered for printing
+ print hEtwNewMc $szMcLine;
+
+ } elsif ( $fInTaskList ){
if ( !$fCurrInsertDone ){
@@ -617,6 +671,12 @@ sub szpad {
}
+if ( $iPrintLevel >= 2 ){
+ print "Keywords found in $szEtwBaseMc \n";
+ for $i ( 0 ... $#rgsKeywords ){
+ print "\t\tEtwKeyword[$i] = { $rgsKeywords[$i]{Name}, $rgsKeywords[$i]{Mask} }\n";
+ }
+}
# -----------------------------------------------------------------------------------------------------------------------------------------
#
@@ -652,11 +712,23 @@ sub szpad {
}
-print hOsEventTraceHxxHdrIns <<__OSEVENTTRACEHXXEPILOG__;
+print hOsEventTraceHxxHdrIns <<__OSEVENTTRACEHXXMIDDLE__;
etguidOsTraceBase // general tags autogen'd before this one
};
+enum OSEventTraceKeywordGUID : ULONGLONG
+{
+__OSEVENTTRACEHXXMIDDLE__
+
+for $i ( 0 .. $#rgsKeywords ){
+ # example: _etguidKeywordBfResMgr = 0x00000400,
+ print hOsEventTraceHxxHdrIns " _etguidKeyword$rgsKeywords[$i]{Name} = $rgsKeywords[$i]{Mask},\n";
+}
+
+print hOsEventTraceHxxHdrIns <<__OSEVENTTRACEHXXEPILOG__;
+};
+
__OSEVENTTRACEHXXEPILOG__
diff --git a/dev/ese/src/_lz4/CMakeLists.txt b/dev/ese/src/_lz4/CMakeLists.txt
new file mode 100644
index 00000000..a4375cd1
--- /dev/null
+++ b/dev/ese/src/_lz4/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+
+add_compile_definitions(_UNICODE)
+add_compile_definitions(UNICODE)
+
+add_library(_lz4 STATIC
+ lz4.c)
+
+# Makes the headers in this directory available to consumers
+target_include_directories(_lz4 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/dev/ese/src/_lz4/lz4.c b/dev/ese/src/_lz4/lz4.c
new file mode 100644
index 00000000..c2f504ef
--- /dev/null
+++ b/dev/ese/src/_lz4/lz4.c
@@ -0,0 +1,2495 @@
+/*
+ LZ4 - Fast LZ compression algorithm
+ Copyright (C) 2011-2020, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - LZ4 homepage : http://www.lz4.org
+ - LZ4 source repository : https://github.com/lz4/lz4
+*/
+
+/*-************************************
+* Tuning parameters
+**************************************/
+/*
+ * LZ4_HEAPMODE :
+ * Select how default compression functions will allocate memory for their hash table,
+ * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).
+ */
+#ifndef LZ4_HEAPMODE
+# define LZ4_HEAPMODE 0
+#endif
+
+/*
+ * LZ4_ACCELERATION_DEFAULT :
+ * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0
+ */
+#define LZ4_ACCELERATION_DEFAULT 1
+/*
+ * LZ4_ACCELERATION_MAX :
+ * Any "acceleration" value higher than this threshold
+ * get treated as LZ4_ACCELERATION_MAX instead (fix #876)
+ */
+#define LZ4_ACCELERATION_MAX 65537
+
+
+/*-************************************
+* CPU Feature Detection
+**************************************/
+/* LZ4_FORCE_MEMORY_ACCESS
+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
+ * The below switch allow to select different access method for improved performance.
+ * Method 0 (default) : use `memcpy()`. Safe and portable.
+ * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
+ * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
+ * Method 2 : direct access. This method is portable but violate C standard.
+ * It can generate buggy code on targets which assembly generation depends on alignment.
+ * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
+ * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
+ * Prefer these methods in priority order (0 > 1 > 2)
+ */
+#ifndef LZ4_FORCE_MEMORY_ACCESS /* can be defined externally */
+# if defined(__GNUC__) && \
+ ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) \
+ || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
+# define LZ4_FORCE_MEMORY_ACCESS 2
+# elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__)
+# define LZ4_FORCE_MEMORY_ACCESS 1
+# endif
+#endif
+
+/*
+ * LZ4_FORCE_SW_BITCOUNT
+ * Define this parameter if your target system or compiler does not support hardware bit count
+ */
+#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for WinCE doesn't support Hardware bit count */
+# undef LZ4_FORCE_SW_BITCOUNT /* avoid double def */
+# define LZ4_FORCE_SW_BITCOUNT
+#endif
+
+
+
+/*-************************************
+* Dependency
+**************************************/
+/*
+ * LZ4_SRC_INCLUDED:
+ * Amalgamation flag, whether lz4.c is included
+ */
+#ifndef LZ4_SRC_INCLUDED
+# define LZ4_SRC_INCLUDED 1
+#endif
+
+#ifndef LZ4_STATIC_LINKING_ONLY
+#define LZ4_STATIC_LINKING_ONLY
+#endif
+
+#ifndef LZ4_DISABLE_DEPRECATE_WARNINGS
+#define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */
+#endif
+
+#define LZ4_STATIC_LINKING_ONLY /* LZ4_DISTANCE_MAX */
+#include "lz4.h"
+/* see also "memory routines" below */
+
+
+/*-************************************
+* Compiler Options
+**************************************/
+#if defined(_MSC_VER) && (_MSC_VER >= 1400) /* Visual Studio 2005+ */
+# include /* only present in VS2005+ */
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+#endif /* _MSC_VER */
+
+#ifndef LZ4_FORCE_INLINE
+# ifdef _MSC_VER /* Visual Studio */
+# define LZ4_FORCE_INLINE static __forceinline
+# else
+# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
+# ifdef __GNUC__
+# define LZ4_FORCE_INLINE static inline __attribute__((always_inline))
+# else
+# define LZ4_FORCE_INLINE static inline
+# endif
+# else
+# define LZ4_FORCE_INLINE static
+# endif /* __STDC_VERSION__ */
+# endif /* _MSC_VER */
+#endif /* LZ4_FORCE_INLINE */
+
+/* LZ4_FORCE_O2 and LZ4_FORCE_INLINE
+ * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8,
+ * together with a simple 8-byte copy loop as a fall-back path.
+ * However, this optimization hurts the decompression speed by >30%,
+ * because the execution does not go to the optimized loop
+ * for typical compressible data, and all of the preamble checks
+ * before going to the fall-back path become useless overhead.
+ * This optimization happens only with the -O3 flag, and -O2 generates
+ * a simple 8-byte copy loop.
+ * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy8
+ * functions are annotated with __attribute__((optimize("O2"))),
+ * and also LZ4_wildCopy8 is forcibly inlined, so that the O2 attribute
+ * of LZ4_wildCopy8 does not affect the compression speed.
+ */
+#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__)
+# define LZ4_FORCE_O2 __attribute__((optimize("O2")))
+# undef LZ4_FORCE_INLINE
+# define LZ4_FORCE_INLINE static __inline __attribute__((optimize("O2"),always_inline))
+#else
+# define LZ4_FORCE_O2
+#endif
+
+#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
+# define expect(expr,value) (__builtin_expect ((expr),(value)) )
+#else
+# define expect(expr,value) (expr)
+#endif
+
+#ifndef likely
+#define likely(expr) expect((expr) != 0, 1)
+#endif
+#ifndef unlikely
+#define unlikely(expr) expect((expr) != 0, 0)
+#endif
+
+/* Should the alignment test prove unreliable, for some reason,
+ * it can be disabled by setting LZ4_ALIGN_TEST to 0 */
+#ifndef LZ4_ALIGN_TEST /* can be externally provided */
+# define LZ4_ALIGN_TEST 1
+#endif
+
+
+/*-************************************
+* Memory routines
+**************************************/
+#ifdef LZ4_USER_MEMORY_FUNCTIONS
+/* memory management functions can be customized by user project.
+ * Below functions must exist somewhere in the Project
+ * and be available at link time */
+void* LZ4_malloc(size_t s);
+void* LZ4_calloc(size_t n, size_t s);
+void LZ4_free(void* p);
+# define ALLOC(s) LZ4_malloc(s)
+# define ALLOC_AND_ZERO(s) LZ4_calloc(1,s)
+# define FREEMEM(p) LZ4_free(p)
+#else
+# include /* malloc, calloc, free */
+# define ALLOC(s) malloc(s)
+# define ALLOC_AND_ZERO(s) calloc(1,s)
+# define FREEMEM(p) free(p)
+#endif
+
+#include /* memset, memcpy */
+#define MEM_INIT(p,v,s) memset((p),(v),(s))
+
+
+/*-************************************
+* Common Constants
+**************************************/
+#define MINMATCH 4
+
+#define WILDCOPYLENGTH 8
+#define LASTLITERALS 5 /* see ../doc/lz4_Block_format.md#parsing-restrictions */
+#define MFLIMIT 12 /* see ../doc/lz4_Block_format.md#parsing-restrictions */
+#define MATCH_SAFEGUARD_DISTANCE ((2*WILDCOPYLENGTH) - MINMATCH) /* ensure it's possible to write 2 x wildcopyLength without overflowing output buffer */
+#define FASTLOOP_SAFE_DISTANCE 64
+static const int LZ4_minLength = (MFLIMIT+1);
+
+#define KB *(1 <<10)
+#define MB *(1 <<20)
+#define GB *(1U<<30)
+
+#define LZ4_DISTANCE_ABSOLUTE_MAX 65535
+#if (LZ4_DISTANCE_MAX > LZ4_DISTANCE_ABSOLUTE_MAX) /* max supported by LZ4 format */
+# error "LZ4_DISTANCE_MAX is too big : must be <= 65535"
+#endif
+
+#define ML_BITS 4
+#define ML_MASK ((1U<=1)
+# include
+#else
+# ifndef assert
+# define assert(condition) ((void)0)
+# endif
+#endif
+
+#define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use after variable declarations */
+
+#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2)
+# include
+ static int g_debuglog_enable = 1;
+# define DEBUGLOG(l, ...) { \
+ if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \
+ fprintf(stderr, __FILE__ ": "); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, " \n"); \
+ } }
+#else
+# define DEBUGLOG(l, ...) {} /* disabled */
+#endif
+
+static int LZ4_isAligned(const void* ptr, size_t alignment)
+{
+ return ((size_t)ptr & (alignment -1)) == 0;
+}
+
+
+/*-************************************
+* Types
+**************************************/
+#include
+#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+# include
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef uint32_t U32;
+ typedef int32_t S32;
+ typedef uint64_t U64;
+ typedef uintptr_t uptrval;
+#else
+# if UINT_MAX != 4294967295UL
+# error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4"
+# endif
+ typedef unsigned char BYTE;
+ typedef unsigned short U16;
+ typedef unsigned int U32;
+ typedef signed int S32;
+ typedef unsigned long long U64;
+ typedef size_t uptrval; /* generally true, except OpenVMS-64 */
+#endif
+
+#if defined(__x86_64__)
+ typedef U64 reg_t; /* 64-bits in x32 mode */
+#else
+ typedef size_t reg_t; /* 32-bits in x32 mode */
+#endif
+
+typedef enum {
+ notLimited = 0,
+ limitedOutput = 1,
+ fillOutput = 2
+} limitedOutput_directive;
+
+
+/*-************************************
+* Reading and writing into memory
+**************************************/
+
+/**
+ * LZ4 relies on memcpy with a constant size being inlined. In freestanding
+ * environments, the compiler can't assume the implementation of memcpy() is
+ * standard compliant, so it can't apply its specialized memcpy() inlining
+ * logic. When possible, use __builtin_memcpy() to tell the compiler to analyze
+ * memcpy() as if it were standard compliant, so it can inline it in freestanding
+ * environments. This is needed when decompressing the Linux Kernel, for example.
+ */
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size)
+#else
+#define LZ4_memcpy(dst, src, size) memcpy(dst, src, size)
+#endif
+
+static unsigned LZ4_isLittleEndian(void)
+{
+ const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
+ return one.c[0];
+}
+
+
+#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)
+/* lie to the compiler about data alignment; use with caution */
+
+static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; }
+static U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; }
+static reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; }
+
+static void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
+static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
+
+#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1)
+
+/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
+/* currently only defined for gcc and icc */
+typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) unalign;
+
+static U16 LZ4_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
+static U32 LZ4_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
+static reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArch; }
+
+static void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
+static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
+
+#else /* safe and portable access using memcpy() */
+
+static U16 LZ4_read16(const void* memPtr)
+{
+ U16 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+static U32 LZ4_read32(const void* memPtr)
+{
+ U32 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+static reg_t LZ4_read_ARCH(const void* memPtr)
+{
+ reg_t val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;
+}
+
+static void LZ4_write16(void* memPtr, U16 value)
+{
+ LZ4_memcpy(memPtr, &value, sizeof(value));
+}
+
+static void LZ4_write32(void* memPtr, U32 value)
+{
+ LZ4_memcpy(memPtr, &value, sizeof(value));
+}
+
+#endif /* LZ4_FORCE_MEMORY_ACCESS */
+
+
+static U16 LZ4_readLE16(const void* memPtr)
+{
+ if (LZ4_isLittleEndian()) {
+ return LZ4_read16(memPtr);
+ } else {
+ const BYTE* p = (const BYTE*)memPtr;
+ return (U16)((U16)p[0] + (p[1]<<8));
+ }
+}
+
+static void LZ4_writeLE16(void* memPtr, U16 value)
+{
+ if (LZ4_isLittleEndian()) {
+ LZ4_write16(memPtr, value);
+ } else {
+ BYTE* p = (BYTE*)memPtr;
+ p[0] = (BYTE) value;
+ p[1] = (BYTE)(value>>8);
+ }
+}
+
+/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */
+LZ4_FORCE_INLINE
+void LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd)
+{
+ BYTE* d = (BYTE*)dstPtr;
+ const BYTE* s = (const BYTE*)srcPtr;
+ BYTE* const e = (BYTE*)dstEnd;
+
+ do { LZ4_memcpy(d,s,8); d+=8; s+=8; } while (d= 16. */
+LZ4_FORCE_INLINE void
+LZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd)
+{
+ BYTE* d = (BYTE*)dstPtr;
+ const BYTE* s = (const BYTE*)srcPtr;
+ BYTE* const e = (BYTE*)dstEnd;
+
+ do { LZ4_memcpy(d,s,16); LZ4_memcpy(d+16,s+16,16); d+=32; s+=32; } while (d= dstPtr + MINMATCH
+ * - there is at least 8 bytes available to write after dstEnd */
+LZ4_FORCE_INLINE void
+LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)
+{
+ BYTE v[8];
+
+ assert(dstEnd >= dstPtr + MINMATCH);
+
+ switch(offset) {
+ case 1:
+ MEM_INIT(v, *srcPtr, 8);
+ break;
+ case 2:
+ LZ4_memcpy(v, srcPtr, 2);
+ LZ4_memcpy(&v[2], srcPtr, 2);
+ LZ4_memcpy(&v[4], v, 4);
+ break;
+ case 4:
+ LZ4_memcpy(v, srcPtr, 4);
+ LZ4_memcpy(&v[4], srcPtr, 4);
+ break;
+ default:
+ LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset);
+ return;
+ }
+
+ LZ4_memcpy(dstPtr, v, 8);
+ dstPtr += 8;
+ while (dstPtr < dstEnd) {
+ LZ4_memcpy(dstPtr, v, 8);
+ dstPtr += 8;
+ }
+}
+#endif
+
+
+/*-************************************
+* Common functions
+**************************************/
+static unsigned LZ4_NbCommonBytes (reg_t val)
+{
+ assert(val != 0);
+ if (LZ4_isLittleEndian()) {
+ if (sizeof(val) == 8) {
+# if defined(_MSC_VER) && (_MSC_VER >= 1800) && defined(_M_AMD64) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ /* x64 CPUS without BMI support interpret `TZCNT` as `REP BSF` */
+ return (unsigned)_tzcnt_u64(val) >> 3;
+# elif defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanForward64(&r, (U64)val);
+ return (unsigned)r >> 3;
+# elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \
+ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \
+ !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (unsigned)__builtin_ctzll((U64)val) >> 3;
+# else
+ const U64 m = 0x0101010101010101ULL;
+ val ^= val - 1;
+ return (unsigned)(((U64)((val & (m - 1)) * m)) >> 56);
+# endif
+ } else /* 32 bits */ {
+# if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r;
+ _BitScanForward(&r, (U32)val);
+ return (unsigned)r >> 3;
+# elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \
+ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \
+ !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (unsigned)__builtin_ctz((U32)val) >> 3;
+# else
+ const U32 m = 0x01010101;
+ return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24;
+# endif
+ }
+ } else /* Big Endian CPU */ {
+ if (sizeof(val)==8) {
+# if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \
+ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \
+ !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (unsigned)__builtin_clzll((U64)val) >> 3;
+# else
+#if 1
+ /* this method is probably faster,
+ * but adds a 128 bytes lookup table */
+ static const unsigned char ctz7_tab[128] = {
+ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+ };
+ U64 const mask = 0x0101010101010101ULL;
+ U64 const t = (((val >> 8) - mask) | val) & mask;
+ return ctz7_tab[(t * 0x0080402010080402ULL) >> 57];
+#else
+ /* this method doesn't consume memory space like the previous one,
+ * but it contains several branches,
+ * that may end up slowing execution */
+ static const U32 by32 = sizeof(val)*4; /* 32 on 64 bits (goal), 16 on 32 bits.
+ Just to avoid some static analyzer complaining about shift by 32 on 32-bits target.
+ Note that this code path is never triggered in 32-bits mode. */
+ unsigned r;
+ if (!(val>>by32)) { r=4; } else { r=0; val>>=by32; }
+ if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+ r += (!val);
+ return r;
+#endif
+# endif
+ } else /* 32 bits */ {
+# if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \
+ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \
+ !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (unsigned)__builtin_clz((U32)val) >> 3;
+# else
+ val >>= 8;
+ val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) |
+ (val + 0x00FF0000)) >> 24;
+ return (unsigned)val ^ 3;
+# endif
+ }
+ }
+}
+
+
+#define STEPSIZE sizeof(reg_t)
+LZ4_FORCE_INLINE
+unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
+{
+ const BYTE* const pStart = pIn;
+
+ if (likely(pIn < pInLimit-(STEPSIZE-1))) {
+ reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);
+ if (!diff) {
+ pIn+=STEPSIZE; pMatch+=STEPSIZE;
+ } else {
+ return LZ4_NbCommonBytes(diff);
+ } }
+
+ while (likely(pIn < pInLimit-(STEPSIZE-1))) {
+ reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);
+ if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }
+ pIn += LZ4_NbCommonBytes(diff);
+ return (unsigned)(pIn - pStart);
+ }
+
+ if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }
+ if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }
+ if ((pIn compression run slower on incompressible data */
+
+
+/*-************************************
+* Local Structures and types
+**************************************/
+typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t;
+
+/**
+ * This enum distinguishes several different modes of accessing previous
+ * content in the stream.
+ *
+ * - noDict : There is no preceding content.
+ * - withPrefix64k : Table entries up to ctx->dictSize before the current blob
+ * blob being compressed are valid and refer to the preceding
+ * content (of length ctx->dictSize), which is available
+ * contiguously preceding in memory the content currently
+ * being compressed.
+ * - usingExtDict : Like withPrefix64k, but the preceding content is somewhere
+ * else in memory, starting at ctx->dictionary with length
+ * ctx->dictSize.
+ * - usingDictCtx : Like usingExtDict, but everything concerning the preceding
+ * content is in a separate context, pointed to by
+ * ctx->dictCtx. ctx->dictionary, ctx->dictSize, and table
+ * entries in the current context that refer to positions
+ * preceding the beginning of the current compression are
+ * ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx
+ * ->dictSize describe the location and size of the preceding
+ * content, and matches are found by looking in the ctx
+ * ->dictCtx->hashTable.
+ */
+typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive;
+typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;
+
+
+/*-************************************
+* Local Utils
+**************************************/
+int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }
+const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; }
+int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); }
+int LZ4_sizeofState(void) { return LZ4_STREAMSIZE; }
+
+
+/*-************************************
+* Internal Definitions used in Tests
+**************************************/
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize);
+
+int LZ4_decompress_safe_forceExtDict(const char* source, char* dest,
+ int compressedSize, int maxOutputSize,
+ const void* dictStart, size_t dictSize);
+
+#if defined (__cplusplus)
+}
+#endif
+
+/*-******************************
+* Compression functions
+********************************/
+LZ4_FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType)
+{
+ if (tableType == byU16)
+ return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
+ else
+ return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
+}
+
+LZ4_FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType)
+{
+ const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;
+ if (LZ4_isLittleEndian()) {
+ const U64 prime5bytes = 889523592379ULL;
+ return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));
+ } else {
+ const U64 prime8bytes = 11400714785074694791ULL;
+ return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));
+ }
+}
+
+LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType)
+{
+ if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType);
+ return LZ4_hash4(LZ4_read32(p), tableType);
+}
+
+LZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType)
+{
+ switch (tableType)
+ {
+ default: /* fallthrough */
+ case clearedTable: { /* illegal! */ assert(0); return; }
+ case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = NULL; return; }
+ case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = 0; return; }
+ case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = 0; return; }
+ }
+}
+
+LZ4_FORCE_INLINE void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType)
+{
+ switch (tableType)
+ {
+ default: /* fallthrough */
+ case clearedTable: /* fallthrough */
+ case byPtr: { /* illegal! */ assert(0); return; }
+ case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; }
+ case byU16: { U16* hashTable = (U16*) tableBase; assert(idx < 65536); hashTable[h] = (U16)idx; return; }
+ }
+}
+
+LZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h,
+ void* tableBase, tableType_t const tableType,
+ const BYTE* srcBase)
+{
+ switch (tableType)
+ {
+ case clearedTable: { /* illegal! */ assert(0); return; }
+ case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }
+ case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }
+ case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }
+ }
+}
+
+LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ U32 const h = LZ4_hashPosition(p, tableType);
+ LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
+}
+
+/* LZ4_getIndexOnHash() :
+ * Index of match position registered in hash table.
+ * hash position must be calculated by using base+index, or dictBase+index.
+ * Assumption 1 : only valid if tableType == byU32 or byU16.
+ * Assumption 2 : h is presumed valid (within limits of hash table)
+ */
+LZ4_FORCE_INLINE U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType)
+{
+ LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2);
+ if (tableType == byU32) {
+ const U32* const hashTable = (const U32*) tableBase;
+ assert(h < (1U << (LZ4_MEMORY_USAGE-2)));
+ return hashTable[h];
+ }
+ if (tableType == byU16) {
+ const U16* const hashTable = (const U16*) tableBase;
+ assert(h < (1U << (LZ4_MEMORY_USAGE-1)));
+ return hashTable[h];
+ }
+ assert(0); return 0; /* forbidden case */
+}
+
+static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ if (tableType == byPtr) { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; }
+ if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h] + srcBase; }
+ { const U16* const hashTable = (const U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
+}
+
+LZ4_FORCE_INLINE const BYTE*
+LZ4_getPosition(const BYTE* p,
+ const void* tableBase, tableType_t tableType,
+ const BYTE* srcBase)
+{
+ U32 const h = LZ4_hashPosition(p, tableType);
+ return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
+}
+
+LZ4_FORCE_INLINE void
+LZ4_prepareTable(LZ4_stream_t_internal* const cctx,
+ const int inputSize,
+ const tableType_t tableType) {
+ /* If the table hasn't been used, it's guaranteed to be zeroed out, and is
+ * therefore safe to use no matter what mode we're in. Otherwise, we figure
+ * out if it's safe to leave as is or whether it needs to be reset.
+ */
+ if ((tableType_t)cctx->tableType != clearedTable) {
+ assert(inputSize >= 0);
+ if ((tableType_t)cctx->tableType != tableType
+ || ((tableType == byU16) && cctx->currentOffset + (unsigned)inputSize >= 0xFFFFU)
+ || ((tableType == byU32) && cctx->currentOffset > 1 GB)
+ || tableType == byPtr
+ || inputSize >= 4 KB)
+ {
+ DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx);
+ MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE);
+ cctx->currentOffset = 0;
+ cctx->tableType = (U32)clearedTable;
+ } else {
+ DEBUGLOG(4, "LZ4_prepareTable: Re-use hash table (no reset)");
+ }
+ }
+
+ /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back, is faster
+ * than compressing without a gap. However, compressing with
+ * currentOffset == 0 is faster still, so we preserve that case.
+ */
+ if (cctx->currentOffset != 0 && tableType == byU32) {
+ DEBUGLOG(5, "LZ4_prepareTable: adding 64KB to currentOffset");
+ cctx->currentOffset += 64 KB;
+ }
+
+ /* Finally, clear history */
+ cctx->dictCtx = NULL;
+ cctx->dictionary = NULL;
+ cctx->dictSize = 0;
+}
+
+/** LZ4_compress_generic() :
+ * inlined, to ensure branches are decided at compilation time.
+ * Presumed already validated at this stage:
+ * - source != NULL
+ * - inputSize > 0
+ */
+LZ4_FORCE_INLINE int LZ4_compress_generic_validated(
+ LZ4_stream_t_internal* const cctx,
+ const char* const source,
+ char* const dest,
+ const int inputSize,
+ int *inputConsumed, /* only written when outputDirective == fillOutput */
+ const int maxOutputSize,
+ const limitedOutput_directive outputDirective,
+ const tableType_t tableType,
+ const dict_directive dictDirective,
+ const dictIssue_directive dictIssue,
+ const int acceleration)
+{
+ int result;
+ const BYTE* ip = (const BYTE*) source;
+
+ U32 const startIndex = cctx->currentOffset;
+ const BYTE* base = (const BYTE*) source - startIndex;
+ const BYTE* lowLimit;
+
+ const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx;
+ const BYTE* const dictionary =
+ dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary;
+ const U32 dictSize =
+ dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize;
+ const U32 dictDelta = (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0; /* make indexes in dictCtx comparable with index in current context */
+
+ int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx);
+ U32 const prefixIdxLimit = startIndex - dictSize; /* used when dictDirective == dictSmall */
+ const BYTE* const dictEnd = dictionary ? dictionary + dictSize : dictionary;
+ const BYTE* anchor = (const BYTE*) source;
+ const BYTE* const iend = ip + inputSize;
+ const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1;
+ const BYTE* const matchlimit = iend - LASTLITERALS;
+
+ /* the dictCtx currentOffset is indexed on the start of the dictionary,
+ * while a dictionary in the current context precedes the currentOffset */
+ const BYTE* dictBase = !dictionary ? NULL : (dictDirective == usingDictCtx) ?
+ dictionary + dictSize - dictCtx->currentOffset :
+ dictionary + dictSize - startIndex;
+
+ BYTE* op = (BYTE*) dest;
+ BYTE* const olimit = op + maxOutputSize;
+
+ U32 offset = 0;
+ U32 forwardH;
+
+ DEBUGLOG(5, "LZ4_compress_generic_validated: srcSize=%i, tableType=%u", inputSize, tableType);
+ assert(ip != NULL);
+ /* If init conditions are not met, we don't have to mark stream
+ * as having dirty context, since no action was taken yet */
+ if (outputDirective == fillOutput && maxOutputSize < 1) { return 0; } /* Impossible to store anything */
+ if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) { return 0; } /* Size too large (not within 64K limit) */
+ if (tableType==byPtr) assert(dictDirective==noDict); /* only supported use case with byPtr */
+ assert(acceleration >= 1);
+
+ lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0);
+
+ /* Update context state */
+ if (dictDirective == usingDictCtx) {
+ /* Subsequent linked blocks can't use the dictionary. */
+ /* Instead, they use the block we just compressed. */
+ cctx->dictCtx = NULL;
+ cctx->dictSize = (U32)inputSize;
+ } else {
+ cctx->dictSize += (U32)inputSize;
+ }
+ cctx->currentOffset += (U32)inputSize;
+ cctx->tableType = (U32)tableType;
+
+ if (inputSizehashTable, tableType, base);
+ ip++; forwardH = LZ4_hashPosition(ip, tableType);
+
+ /* Main Loop */
+ for ( ; ; ) {
+ const BYTE* match;
+ BYTE* token;
+ const BYTE* filledIp;
+
+ /* Find a match */
+ if (tableType == byPtr) {
+ const BYTE* forwardIp = ip;
+ int step = 1;
+ int searchMatchNb = acceleration << LZ4_skipTrigger;
+ do {
+ U32 const h = forwardH;
+ ip = forwardIp;
+ forwardIp += step;
+ step = (searchMatchNb++ >> LZ4_skipTrigger);
+
+ if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;
+ assert(ip < mflimitPlusOne);
+
+ match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);
+ forwardH = LZ4_hashPosition(forwardIp, tableType);
+ LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);
+
+ } while ( (match+LZ4_DISTANCE_MAX < ip)
+ || (LZ4_read32(match) != LZ4_read32(ip)) );
+
+ } else { /* byU32, byU16 */
+
+ const BYTE* forwardIp = ip;
+ int step = 1;
+ int searchMatchNb = acceleration << LZ4_skipTrigger;
+ do {
+ U32 const h = forwardH;
+ U32 const current = (U32)(forwardIp - base);
+ U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);
+ assert(matchIndex <= current);
+ assert(forwardIp - base < (ptrdiff_t)(2 GB - 1));
+ ip = forwardIp;
+ forwardIp += step;
+ step = (searchMatchNb++ >> LZ4_skipTrigger);
+
+ if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;
+ assert(ip < mflimitPlusOne);
+
+ if (dictDirective == usingDictCtx) {
+ if (matchIndex < startIndex) {
+ /* there was no match, try the dictionary */
+ assert(tableType == byU32);
+ matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);
+ match = dictBase + matchIndex;
+ matchIndex += dictDelta; /* make dictCtx index comparable with current context */
+ lowLimit = dictionary;
+ } else {
+ match = base + matchIndex;
+ lowLimit = (const BYTE*)source;
+ }
+ } else if (dictDirective==usingExtDict) {
+ if (matchIndex < startIndex) {
+ DEBUGLOG(7, "extDict candidate: matchIndex=%5u < startIndex=%5u", matchIndex, startIndex);
+ assert(startIndex - matchIndex >= MINMATCH);
+ match = dictBase + matchIndex;
+ lowLimit = dictionary;
+ } else {
+ match = base + matchIndex;
+ lowLimit = (const BYTE*)source;
+ }
+ } else { /* single continuous memory segment */
+ match = base + matchIndex;
+ }
+ forwardH = LZ4_hashPosition(forwardIp, tableType);
+ LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);
+
+ DEBUGLOG(7, "candidate at pos=%u (offset=%u \n", matchIndex, current - matchIndex);
+ if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) { continue; } /* match outside of valid area */
+ assert(matchIndex < current);
+ if ( ((tableType != byU16) || (LZ4_DISTANCE_MAX < LZ4_DISTANCE_ABSOLUTE_MAX))
+ && (matchIndex+LZ4_DISTANCE_MAX < current)) {
+ continue;
+ } /* too far */
+ assert((current - matchIndex) <= LZ4_DISTANCE_MAX); /* match now expected within distance */
+
+ if (LZ4_read32(match) == LZ4_read32(ip)) {
+ if (maybe_extMem) offset = current - matchIndex;
+ break; /* match found */
+ }
+
+ } while(1);
+ }
+
+ /* Catch up */
+ filledIp = ip;
+ while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }
+
+ /* Encode Literals */
+ { unsigned const litLength = (unsigned)(ip - anchor);
+ token = op++;
+ if ((outputDirective == limitedOutput) && /* Check output buffer overflow */
+ (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)) ) {
+ return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */
+ }
+ if ((outputDirective == fillOutput) &&
+ (unlikely(op + (litLength+240)/255 /* litlen */ + litLength /* literals */ + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit))) {
+ op--;
+ goto _last_literals;
+ }
+ if (litLength >= RUN_MASK) {
+ int len = (int)(litLength - RUN_MASK);
+ *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255;
+ *op++ = (BYTE)len;
+ }
+ else *token = (BYTE)(litLength< olimit)) {
+ /* the match was too close to the end, rewind and go to last literals */
+ op = token;
+ goto _last_literals;
+ }
+
+ /* Encode Offset */
+ if (maybe_extMem) { /* static test */
+ DEBUGLOG(6, " with offset=%u (ext if > %i)", offset, (int)(ip - (const BYTE*)source));
+ assert(offset <= LZ4_DISTANCE_MAX && offset > 0);
+ LZ4_writeLE16(op, (U16)offset); op+=2;
+ } else {
+ DEBUGLOG(6, " with offset=%u (same segment)", (U32)(ip - match));
+ assert(ip-match <= LZ4_DISTANCE_MAX);
+ LZ4_writeLE16(op, (U16)(ip - match)); op+=2;
+ }
+
+ /* Encode MatchLength */
+ { unsigned matchCode;
+
+ if ( (dictDirective==usingExtDict || dictDirective==usingDictCtx)
+ && (lowLimit==dictionary) /* match within extDict */ ) {
+ const BYTE* limit = ip + (dictEnd-match);
+ assert(dictEnd > match);
+ if (limit > matchlimit) limit = matchlimit;
+ matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);
+ ip += (size_t)matchCode + MINMATCH;
+ if (ip==limit) {
+ unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit);
+ matchCode += more;
+ ip += more;
+ }
+ DEBUGLOG(6, " with matchLength=%u starting in extDict", matchCode+MINMATCH);
+ } else {
+ matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
+ ip += (size_t)matchCode + MINMATCH;
+ DEBUGLOG(6, " with matchLength=%u", matchCode+MINMATCH);
+ }
+
+ if ((outputDirective) && /* Check output buffer overflow */
+ (unlikely(op + (1 + LASTLITERALS) + (matchCode+240)/255 > olimit)) ) {
+ if (outputDirective == fillOutput) {
+ /* Match description too long : reduce it */
+ U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 1 - LASTLITERALS) * 255;
+ ip -= matchCode - newMatchCode;
+ assert(newMatchCode < matchCode);
+ matchCode = newMatchCode;
+ if (unlikely(ip <= filledIp)) {
+ /* We have already filled up to filledIp so if ip ends up less than filledIp
+ * we have positions in the hash table beyond the current position. This is
+ * a problem if we reuse the hash table. So we have to remove these positions
+ * from the hash table.
+ */
+ const BYTE* ptr;
+ DEBUGLOG(5, "Clearing %u positions", (U32)(filledIp - ip));
+ for (ptr = ip; ptr <= filledIp; ++ptr) {
+ U32 const h = LZ4_hashPosition(ptr, tableType);
+ LZ4_clearHash(h, cctx->hashTable, tableType);
+ }
+ }
+ } else {
+ assert(outputDirective == limitedOutput);
+ return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */
+ }
+ }
+ if (matchCode >= ML_MASK) {
+ *token += ML_MASK;
+ matchCode -= ML_MASK;
+ LZ4_write32(op, 0xFFFFFFFF);
+ while (matchCode >= 4*255) {
+ op+=4;
+ LZ4_write32(op, 0xFFFFFFFF);
+ matchCode -= 4*255;
+ }
+ op += matchCode / 255;
+ *op++ = (BYTE)(matchCode % 255);
+ } else
+ *token += (BYTE)(matchCode);
+ }
+ /* Ensure we have enough space for the last literals. */
+ assert(!(outputDirective == fillOutput && op + 1 + LASTLITERALS > olimit));
+
+ anchor = ip;
+
+ /* Test end of chunk */
+ if (ip >= mflimitPlusOne) break;
+
+ /* Fill table */
+ LZ4_putPosition(ip-2, cctx->hashTable, tableType, base);
+
+ /* Test next position */
+ if (tableType == byPtr) {
+
+ match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);
+ LZ4_putPosition(ip, cctx->hashTable, tableType, base);
+ if ( (match+LZ4_DISTANCE_MAX >= ip)
+ && (LZ4_read32(match) == LZ4_read32(ip)) )
+ { token=op++; *token=0; goto _next_match; }
+
+ } else { /* byU32, byU16 */
+
+ U32 const h = LZ4_hashPosition(ip, tableType);
+ U32 const current = (U32)(ip-base);
+ U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);
+ assert(matchIndex < current);
+ if (dictDirective == usingDictCtx) {
+ if (matchIndex < startIndex) {
+ /* there was no match, try the dictionary */
+ matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);
+ match = dictBase + matchIndex;
+ lowLimit = dictionary; /* required for match length counter */
+ matchIndex += dictDelta;
+ } else {
+ match = base + matchIndex;
+ lowLimit = (const BYTE*)source; /* required for match length counter */
+ }
+ } else if (dictDirective==usingExtDict) {
+ if (matchIndex < startIndex) {
+ match = dictBase + matchIndex;
+ lowLimit = dictionary; /* required for match length counter */
+ } else {
+ match = base + matchIndex;
+ lowLimit = (const BYTE*)source; /* required for match length counter */
+ }
+ } else { /* single memory segment */
+ match = base + matchIndex;
+ }
+ LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);
+ assert(matchIndex < current);
+ if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1)
+ && (((tableType==byU16) && (LZ4_DISTANCE_MAX == LZ4_DISTANCE_ABSOLUTE_MAX)) ? 1 : (matchIndex+LZ4_DISTANCE_MAX >= current))
+ && (LZ4_read32(match) == LZ4_read32(ip)) ) {
+ token=op++;
+ *token=0;
+ if (maybe_extMem) offset = current - matchIndex;
+ DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i",
+ (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source));
+ goto _next_match;
+ }
+ }
+
+ /* Prepare next loop */
+ forwardH = LZ4_hashPosition(++ip, tableType);
+
+ }
+
+_last_literals:
+ /* Encode Last Literals */
+ { size_t lastRun = (size_t)(iend - anchor);
+ if ( (outputDirective) && /* Check output buffer overflow */
+ (op + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > olimit)) {
+ if (outputDirective == fillOutput) {
+ /* adapt lastRun to fill 'dst' */
+ assert(olimit >= op);
+ lastRun = (size_t)(olimit-op) - 1/*token*/;
+ lastRun -= (lastRun + 256 - RUN_MASK) / 256; /*additional length tokens*/
+ } else {
+ assert(outputDirective == limitedOutput);
+ return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */
+ }
+ }
+ DEBUGLOG(6, "Final literal run : %i literals", (int)lastRun);
+ if (lastRun >= RUN_MASK) {
+ size_t accumulator = lastRun - RUN_MASK;
+ *op++ = RUN_MASK << ML_BITS;
+ for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
+ *op++ = (BYTE) accumulator;
+ } else {
+ *op++ = (BYTE)(lastRun< 0);
+ DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", inputSize, result);
+ return result;
+}
+
+/** LZ4_compress_generic() :
+ * inlined, to ensure branches are decided at compilation time;
+ * takes care of src == (NULL, 0)
+ * and forward the rest to LZ4_compress_generic_validated */
+LZ4_FORCE_INLINE int LZ4_compress_generic(
+ LZ4_stream_t_internal* const cctx,
+ const char* const src,
+ char* const dst,
+ const int srcSize,
+ int *inputConsumed, /* only written when outputDirective == fillOutput */
+ const int dstCapacity,
+ const limitedOutput_directive outputDirective,
+ const tableType_t tableType,
+ const dict_directive dictDirective,
+ const dictIssue_directive dictIssue,
+ const int acceleration)
+{
+ DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, dstCapacity=%i",
+ srcSize, dstCapacity);
+
+ if ((U32)srcSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; } /* Unsupported srcSize, too large (or negative) */
+ if (srcSize == 0) { /* src == NULL supported if srcSize == 0 */
+ if (outputDirective != notLimited && dstCapacity <= 0) return 0; /* no output, can't write anything */
+ DEBUGLOG(5, "Generating an empty block");
+ assert(outputDirective == notLimited || dstCapacity >= 1);
+ assert(dst != NULL);
+ dst[0] = 0;
+ if (outputDirective == fillOutput) {
+ assert (inputConsumed != NULL);
+ *inputConsumed = 0;
+ }
+ return 1;
+ }
+ assert(src != NULL);
+
+ return LZ4_compress_generic_validated(cctx, src, dst, srcSize,
+ inputConsumed, /* only written into if outputDirective == fillOutput */
+ dstCapacity, outputDirective,
+ tableType, dictDirective, dictIssue, acceleration);
+}
+
+
+int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+ LZ4_stream_t_internal* const ctx = & LZ4_initStream(state, sizeof(LZ4_stream_t)) -> internal_donotuse;
+ assert(ctx != NULL);
+ if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;
+ if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;
+ if (maxOutputSize >= LZ4_compressBound(inputSize)) {
+ if (inputSize < LZ4_64Klimit) {
+ return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
+ } else {
+ const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;
+ return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);
+ }
+ } else {
+ if (inputSize < LZ4_64Klimit) {
+ return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
+ } else {
+ const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;
+ return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration);
+ }
+ }
+}
+
+/**
+ * LZ4_compress_fast_extState_fastReset() :
+ * A variant of LZ4_compress_fast_extState().
+ *
+ * Using this variant avoids an expensive initialization step. It is only safe
+ * to call if the state buffer is known to be correctly initialized already
+ * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of
+ * "correctly initialized").
+ */
+int LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration)
+{
+ LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse;
+ if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;
+ if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;
+
+ if (dstCapacity >= LZ4_compressBound(srcSize)) {
+ if (srcSize < LZ4_64Klimit) {
+ const tableType_t tableType = byU16;
+ LZ4_prepareTable(ctx, srcSize, tableType);
+ if (ctx->currentOffset) {
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, dictSmall, acceleration);
+ } else {
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);
+ }
+ } else {
+ const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;
+ LZ4_prepareTable(ctx, srcSize, tableType);
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);
+ }
+ } else {
+ if (srcSize < LZ4_64Klimit) {
+ const tableType_t tableType = byU16;
+ LZ4_prepareTable(ctx, srcSize, tableType);
+ if (ctx->currentOffset) {
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration);
+ } else {
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);
+ }
+ } else {
+ const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;
+ LZ4_prepareTable(ctx, srcSize, tableType);
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);
+ }
+ }
+}
+
+
+int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+ int result;
+#if (LZ4_HEAPMODE)
+ LZ4_stream_t* ctxPtr = ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
+ if (ctxPtr == NULL) return 0;
+#else
+ LZ4_stream_t ctx;
+ LZ4_stream_t* const ctxPtr = &ctx;
+#endif
+ result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);
+
+#if (LZ4_HEAPMODE)
+ FREEMEM(ctxPtr);
+#endif
+ return result;
+}
+
+
+int LZ4_compress_default(const char* src, char* dst, int srcSize, int maxOutputSize)
+{
+ return LZ4_compress_fast(src, dst, srcSize, maxOutputSize, 1);
+}
+
+
+/* Note!: This function leaves the stream in an unclean/broken state!
+ * It is not safe to subsequently use the same state with a _fastReset() or
+ * _continue() call without resetting it. */
+static int LZ4_compress_destSize_extState (LZ4_stream_t* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize)
+{
+ void* const s = LZ4_initStream(state, sizeof (*state));
+ assert(s != NULL); (void)s;
+
+ if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */
+ return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);
+ } else {
+ if (*srcSizePtr < LZ4_64Klimit) {
+ return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, byU16, noDict, noDictIssue, 1);
+ } else {
+ tableType_t const addrMode = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;
+ return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, addrMode, noDict, noDictIssue, 1);
+ } }
+}
+
+
+int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)
+{
+#if (LZ4_HEAPMODE)
+ LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
+ if (ctx == NULL) return 0;
+#else
+ LZ4_stream_t ctxBody;
+ LZ4_stream_t* ctx = &ctxBody;
+#endif
+
+ int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);
+
+#if (LZ4_HEAPMODE)
+ FREEMEM(ctx);
+#endif
+ return result;
+}
+
+
+
+/*-******************************
+* Streaming functions
+********************************/
+
+LZ4_stream_t* LZ4_createStream(void)
+{
+ LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));
+ LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */
+ DEBUGLOG(4, "LZ4_createStream %p", lz4s);
+ if (lz4s == NULL) return NULL;
+ LZ4_initStream(lz4s, sizeof(*lz4s));
+ return lz4s;
+}
+
+static size_t LZ4_stream_t_alignment(void)
+{
+#if LZ4_ALIGN_TEST
+ typedef struct { char c; LZ4_stream_t t; } t_a;
+ return sizeof(t_a) - sizeof(LZ4_stream_t);
+#else
+ return 1; /* effectively disabled */
+#endif
+}
+
+LZ4_stream_t* LZ4_initStream (void* buffer, size_t size)
+{
+ DEBUGLOG(5, "LZ4_initStream");
+ if (buffer == NULL) { return NULL; }
+ if (size < sizeof(LZ4_stream_t)) { return NULL; }
+ if (!LZ4_isAligned(buffer, LZ4_stream_t_alignment())) return NULL;
+ MEM_INIT(buffer, 0, sizeof(LZ4_stream_t_internal));
+ return (LZ4_stream_t*)buffer;
+}
+
+/* resetStream is now deprecated,
+ * prefer initStream() which is more general */
+void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
+{
+ DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream);
+ MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t_internal));
+}
+
+void LZ4_resetStream_fast(LZ4_stream_t* ctx) {
+ LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32);
+}
+
+int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
+{
+ if (!LZ4_stream) return 0; /* support free on NULL */
+ DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream);
+ FREEMEM(LZ4_stream);
+ return (0);
+}
+
+
+#define HASH_UNIT sizeof(reg_t)
+int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)
+{
+ LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse;
+ const tableType_t tableType = byU32;
+ const BYTE* p = (const BYTE*)dictionary;
+ const BYTE* const dictEnd = p + dictSize;
+ const BYTE* base;
+
+ DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict);
+
+ /* It's necessary to reset the context,
+ * and not just continue it with prepareTable()
+ * to avoid any risk of generating overflowing matchIndex
+ * when compressing using this dictionary */
+ LZ4_resetStream(LZ4_dict);
+
+ /* We always increment the offset by 64 KB, since, if the dict is longer,
+ * we truncate it to the last 64k, and if it's shorter, we still want to
+ * advance by a whole window length so we can provide the guarantee that
+ * there are only valid offsets in the window, which allows an optimization
+ * in LZ4_compress_fast_continue() where it uses noDictIssue even when the
+ * dictionary isn't a full 64k. */
+ dict->currentOffset += 64 KB;
+
+ if (dictSize < (int)HASH_UNIT) {
+ return 0;
+ }
+
+ if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;
+ base = dictEnd - dict->currentOffset;
+ dict->dictionary = p;
+ dict->dictSize = (U32)(dictEnd - p);
+ dict->tableType = (U32)tableType;
+
+ while (p <= dictEnd-HASH_UNIT) {
+ LZ4_putPosition(p, dict->hashTable, tableType, base);
+ p+=3;
+ }
+
+ return (int)dict->dictSize;
+}
+
+void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream) {
+ const LZ4_stream_t_internal* dictCtx = dictionaryStream == NULL ? NULL :
+ &(dictionaryStream->internal_donotuse);
+
+ DEBUGLOG(4, "LZ4_attach_dictionary (%p, %p, size %u)",
+ workingStream, dictionaryStream,
+ dictCtx != NULL ? dictCtx->dictSize : 0);
+
+ if (dictCtx != NULL) {
+ /* If the current offset is zero, we will never look in the
+ * external dictionary context, since there is no value a table
+ * entry can take that indicate a miss. In that case, we need
+ * to bump the offset to something non-zero.
+ */
+ if (workingStream->internal_donotuse.currentOffset == 0) {
+ workingStream->internal_donotuse.currentOffset = 64 KB;
+ }
+
+ /* Don't actually attach an empty dictionary.
+ */
+ if (dictCtx->dictSize == 0) {
+ dictCtx = NULL;
+ }
+ }
+ workingStream->internal_donotuse.dictCtx = dictCtx;
+}
+
+
+static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize)
+{
+ assert(nextSize >= 0);
+ if (LZ4_dict->currentOffset + (unsigned)nextSize > 0x80000000) { /* potential ptrdiff_t overflow (32-bits mode) */
+ /* rescale hash table */
+ U32 const delta = LZ4_dict->currentOffset - 64 KB;
+ const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;
+ int i;
+ DEBUGLOG(4, "LZ4_renormDictT");
+ for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0;
+ else LZ4_dict->hashTable[i] -= delta;
+ }
+ LZ4_dict->currentOffset = 64 KB;
+ if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;
+ LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;
+ }
+}
+
+
+int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream,
+ const char* source, char* dest,
+ int inputSize, int maxOutputSize,
+ int acceleration)
+{
+ const tableType_t tableType = byU32;
+ LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse;
+ const BYTE* dictEnd = streamPtr->dictionary + streamPtr->dictSize;
+
+ DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i)", inputSize);
+
+ LZ4_renormDictT(streamPtr, inputSize); /* avoid index overflow */
+ if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;
+ if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;
+
+ /* invalidate tiny dictionaries */
+ if ( (streamPtr->dictSize-1 < 4-1) /* intentional underflow */
+ && (dictEnd != (const BYTE*)source) ) {
+ DEBUGLOG(5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, streamPtr->dictionary);
+ streamPtr->dictSize = 0;
+ streamPtr->dictionary = (const BYTE*)source;
+ dictEnd = (const BYTE*)source;
+ }
+
+ /* Check overlapping input/dictionary space */
+ { const BYTE* sourceEnd = (const BYTE*) source + inputSize;
+ if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) {
+ streamPtr->dictSize = (U32)(dictEnd - sourceEnd);
+ if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;
+ if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;
+ streamPtr->dictionary = dictEnd - streamPtr->dictSize;
+ }
+ }
+
+ /* prefix mode : source data follows dictionary */
+ if (dictEnd == (const BYTE*)source) {
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
+ return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration);
+ else
+ return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration);
+ }
+
+ /* external dictionary mode */
+ { int result;
+ if (streamPtr->dictCtx) {
+ /* We depend here on the fact that dictCtx'es (produced by
+ * LZ4_loadDict) guarantee that their tables contain no references
+ * to offsets between dictCtx->currentOffset - 64 KB and
+ * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe
+ * to use noDictIssue even when the dict isn't a full 64 KB.
+ */
+ if (inputSize > 4 KB) {
+ /* For compressing large blobs, it is faster to pay the setup
+ * cost to copy the dictionary's tables into the active context,
+ * so that the compression loop is only looking into one table.
+ */
+ LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr));
+ result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);
+ } else {
+ result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration);
+ }
+ } else {
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {
+ result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration);
+ } else {
+ result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);
+ }
+ }
+ streamPtr->dictionary = (const BYTE*)source;
+ streamPtr->dictSize = (U32)inputSize;
+ return result;
+ }
+}
+
+
+/* Hidden debug function, to force-test external dictionary mode */
+int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize)
+{
+ LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse;
+ int result;
+
+ LZ4_renormDictT(streamPtr, srcSize);
+
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {
+ result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, dictSmall, 1);
+ } else {
+ result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);
+ }
+
+ streamPtr->dictionary = (const BYTE*)source;
+ streamPtr->dictSize = (U32)srcSize;
+
+ return result;
+}
+
+
+/*! LZ4_saveDict() :
+ * If previously compressed data block is not guaranteed to remain available at its memory location,
+ * save it into a safer place (char* safeBuffer).
+ * Note : you don't need to call LZ4_loadDict() afterwards,
+ * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue().
+ * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error.
+ */
+int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)
+{
+ LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse;
+ const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize;
+
+ if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */
+ if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; }
+
+ if (safeBuffer == NULL) assert(dictSize == 0);
+ if (dictSize > 0)
+ memmove(safeBuffer, previousDictEnd - dictSize, dictSize);
+
+ dict->dictionary = (const BYTE*)safeBuffer;
+ dict->dictSize = (U32)dictSize;
+
+ return dictSize;
+}
+
+
+
+/*-*******************************
+ * Decompression functions
+ ********************************/
+
+typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
+typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive;
+
+#undef MIN
+#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
+
+/* Read the variable-length literal or match length.
+ *
+ * ip - pointer to use as input.
+ * lencheck - end ip. Return an error if ip advances >= lencheck.
+ * loop_check - check ip >= lencheck in body of loop. Returns loop_error if so.
+ * initial_check - check ip >= lencheck before start of loop. Returns initial_error if so.
+ * error (output) - error code. Should be set to 0 before call.
+ */
+typedef enum { loop_error = -2, initial_error = -1, ok = 0 } variable_length_error;
+LZ4_FORCE_INLINE unsigned
+read_variable_length(const BYTE**ip, const BYTE* lencheck,
+ int loop_check, int initial_check,
+ variable_length_error* error)
+{
+ U32 length = 0;
+ U32 s;
+ if (initial_check && unlikely((*ip) >= lencheck)) { /* overflow detection */
+ *error = initial_error;
+ return length;
+ }
+ do {
+ s = **ip;
+ (*ip)++;
+ length += s;
+ if (loop_check && unlikely((*ip) >= lencheck)) { /* overflow detection */
+ *error = loop_error;
+ return length;
+ }
+ } while (s==255);
+
+ return length;
+}
+
+/*! LZ4_decompress_generic() :
+ * This generic decompression function covers all use cases.
+ * It shall be instantiated several times, using different sets of directives.
+ * Note that it is important for performance that this function really get inlined,
+ * in order to remove useless branches during compilation optimization.
+ */
+LZ4_FORCE_INLINE int
+LZ4_decompress_generic(
+ const char* const src,
+ char* const dst,
+ int srcSize,
+ int outputSize, /* If endOnInput==endOnInputSize, this value is `dstCapacity` */
+
+ endCondition_directive endOnInput, /* endOnOutputSize, endOnInputSize */
+ earlyEnd_directive partialDecoding, /* full, partial */
+ dict_directive dict, /* noDict, withPrefix64k, usingExtDict */
+ const BYTE* const lowPrefix, /* always <= dst, == dst when no prefix */
+ const BYTE* const dictStart, /* only if dict==usingExtDict */
+ const size_t dictSize /* note : = 0 if noDict */
+ )
+{
+ if ((src == NULL) || (outputSize < 0)) { return -1; }
+
+ { const BYTE* ip = (const BYTE*) src;
+ const BYTE* const iend = ip + srcSize;
+
+ BYTE* op = (BYTE*) dst;
+ BYTE* const oend = op + outputSize;
+ BYTE* cpy;
+
+ const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize;
+
+ const int safeDecode = (endOnInput==endOnInputSize);
+ const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
+
+
+ /* Set up the "end" pointers for the shortcut. */
+ const BYTE* const shortiend = iend - (endOnInput ? 14 : 8) /*maxLL*/ - 2 /*offset*/;
+ const BYTE* const shortoend = oend - (endOnInput ? 14 : 8) /*maxLL*/ - 18 /*maxML*/;
+
+ const BYTE* match;
+ size_t offset;
+ unsigned token;
+ size_t length;
+
+
+ DEBUGLOG(5, "LZ4_decompress_generic (srcSize:%i, dstSize:%i)", srcSize, outputSize);
+
+ /* Special cases */
+ assert(lowPrefix <= op);
+ if ((endOnInput) && (unlikely(outputSize==0))) {
+ /* Empty output buffer */
+ if (partialDecoding) return 0;
+ return ((srcSize==1) && (*ip==0)) ? 0 : -1;
+ }
+ if ((!endOnInput) && (unlikely(outputSize==0))) { return (*ip==0 ? 1 : -1); }
+ if ((endOnInput) && unlikely(srcSize==0)) { return -1; }
+
+ /* Currently the fast loop shows a regression on qualcomm arm chips. */
+#if LZ4_FAST_DEC_LOOP
+ if ((oend - op) < FASTLOOP_SAFE_DISTANCE) {
+ DEBUGLOG(6, "skip fast decode loop");
+ goto safe_decode;
+ }
+
+ /* Fast loop : decode sequences as long as output < iend-FASTLOOP_SAFE_DISTANCE */
+ while (1) {
+ /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */
+ assert(oend - op >= FASTLOOP_SAFE_DISTANCE);
+ if (endOnInput) { assert(ip < iend); }
+ token = *ip++;
+ length = token >> ML_BITS; /* literal length */
+
+ assert(!endOnInput || ip <= iend); /* ip < iend before the increment */
+
+ /* decode literal length */
+ if (length == RUN_MASK) {
+ variable_length_error error = ok;
+ length += read_variable_length(&ip, iend-RUN_MASK, (int)endOnInput, (int)endOnInput, &error);
+ if (error == initial_error) { goto _output_error; }
+ if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */
+ if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */
+
+ /* copy literals */
+ cpy = op+length;
+ LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);
+ if (endOnInput) { /* LZ4_decompress_safe() */
+ if ((cpy>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; }
+ LZ4_wildCopy32(op, ip, cpy);
+ } else { /* LZ4_decompress_fast() */
+ if (cpy>oend-8) { goto safe_literal_copy; }
+ LZ4_wildCopy8(op, ip, cpy); /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time :
+ * it doesn't know input length, and only relies on end-of-block properties */
+ }
+ ip += length; op = cpy;
+ } else {
+ cpy = op+length;
+ if (endOnInput) { /* LZ4_decompress_safe() */
+ DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length);
+ /* We don't need to check oend, since we check it once for each loop below */
+ if (ip > iend-(16 + 1/*max lit + offset + nextToken*/)) { goto safe_literal_copy; }
+ /* Literals can only be 14, but hope compilers optimize if we copy by a register size */
+ LZ4_memcpy(op, ip, 16);
+ } else { /* LZ4_decompress_fast() */
+ /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time :
+ * it doesn't know input length, and relies on end-of-block properties */
+ LZ4_memcpy(op, ip, 8);
+ if (length > 8) { LZ4_memcpy(op+8, ip+8, 8); }
+ }
+ ip += length; op = cpy;
+ }
+
+ /* get offset */
+ offset = LZ4_readLE16(ip); ip+=2;
+ match = op - offset;
+ assert(match <= op);
+
+ /* get matchlength */
+ length = token & ML_MASK;
+
+ if (length == ML_MASK) {
+ variable_length_error error = ok;
+ if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */
+ length += read_variable_length(&ip, iend - LASTLITERALS + 1, (int)endOnInput, 0, &error);
+ if (error != ok) { goto _output_error; }
+ if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */
+ length += MINMATCH;
+ if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {
+ goto safe_match_copy;
+ }
+ } else {
+ length += MINMATCH;
+ if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {
+ goto safe_match_copy;
+ }
+
+ /* Fastpath check: Avoids a branch in LZ4_wildCopy32 if true */
+ if ((dict == withPrefix64k) || (match >= lowPrefix)) {
+ if (offset >= 8) {
+ assert(match >= lowPrefix);
+ assert(match <= op);
+ assert(op + 18 <= oend);
+
+ LZ4_memcpy(op, match, 8);
+ LZ4_memcpy(op+8, match+8, 8);
+ LZ4_memcpy(op+16, match+16, 2);
+ op += length;
+ continue;
+ } } }
+
+ if (checkOffset && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */
+ /* match starting within external dictionary */
+ if ((dict==usingExtDict) && (match < lowPrefix)) {
+ if (unlikely(op+length > oend-LASTLITERALS)) {
+ if (partialDecoding) {
+ DEBUGLOG(7, "partialDecoding: dictionary match, close to dstEnd");
+ length = MIN(length, (size_t)(oend-op));
+ } else {
+ goto _output_error; /* end-of-block condition violated */
+ } }
+
+ if (length <= (size_t)(lowPrefix-match)) {
+ /* match fits entirely within external dictionary : just copy */
+ memmove(op, dictEnd - (lowPrefix-match), length);
+ op += length;
+ } else {
+ /* match stretches into both external dictionary and current block */
+ size_t const copySize = (size_t)(lowPrefix - match);
+ size_t const restSize = length - copySize;
+ LZ4_memcpy(op, dictEnd - copySize, copySize);
+ op += copySize;
+ if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */
+ BYTE* const endOfMatch = op + restSize;
+ const BYTE* copyFrom = lowPrefix;
+ while (op < endOfMatch) { *op++ = *copyFrom++; }
+ } else {
+ LZ4_memcpy(op, lowPrefix, restSize);
+ op += restSize;
+ } }
+ continue;
+ }
+
+ /* copy match within block */
+ cpy = op + length;
+
+ assert((op <= oend) && (oend-op >= 32));
+ if (unlikely(offset<16)) {
+ LZ4_memcpy_using_offset(op, match, cpy, offset);
+ } else {
+ LZ4_wildCopy32(op, match, cpy);
+ }
+
+ op = cpy; /* wildcopy correction */
+ }
+ safe_decode:
+#endif
+
+ /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */
+ while (1) {
+ token = *ip++;
+ length = token >> ML_BITS; /* literal length */
+
+ assert(!endOnInput || ip <= iend); /* ip < iend before the increment */
+
+ /* A two-stage shortcut for the most common case:
+ * 1) If the literal length is 0..14, and there is enough space,
+ * enter the shortcut and copy 16 bytes on behalf of the literals
+ * (in the fast mode, only 8 bytes can be safely copied this way).
+ * 2) Further if the match length is 4..18, copy 18 bytes in a similar
+ * manner; but we ensure that there's enough space in the output for
+ * those 18 bytes earlier, upon entering the shortcut (in other words,
+ * there is a combined check for both stages).
+ */
+ if ( (endOnInput ? length != RUN_MASK : length <= 8)
+ /* strictly "less than" on input, to re-enter the loop with at least one byte */
+ && likely((endOnInput ? ip < shortiend : 1) & (op <= shortoend)) ) {
+ /* Copy the literals */
+ LZ4_memcpy(op, ip, endOnInput ? 16 : 8);
+ op += length; ip += length;
+
+ /* The second stage: prepare for match copying, decode full info.
+ * If it doesn't work out, the info won't be wasted. */
+ length = token & ML_MASK; /* match length */
+ offset = LZ4_readLE16(ip); ip += 2;
+ match = op - offset;
+ assert(match <= op); /* check overflow */
+
+ /* Do not deal with overlapping matches. */
+ if ( (length != ML_MASK)
+ && (offset >= 8)
+ && (dict==withPrefix64k || match >= lowPrefix) ) {
+ /* Copy the match. */
+ LZ4_memcpy(op + 0, match + 0, 8);
+ LZ4_memcpy(op + 8, match + 8, 8);
+ LZ4_memcpy(op +16, match +16, 2);
+ op += length + MINMATCH;
+ /* Both stages worked, load the next token. */
+ continue;
+ }
+
+ /* The second stage didn't work out, but the info is ready.
+ * Propel it right to the point of match copying. */
+ goto _copy_match;
+ }
+
+ /* decode literal length */
+ if (length == RUN_MASK) {
+ variable_length_error error = ok;
+ length += read_variable_length(&ip, iend-RUN_MASK, (int)endOnInput, (int)endOnInput, &error);
+ if (error == initial_error) { goto _output_error; }
+ if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */
+ if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */
+ }
+
+ /* copy literals */
+ cpy = op+length;
+#if LZ4_FAST_DEC_LOOP
+ safe_literal_copy:
+#endif
+ LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);
+ if ( ((endOnInput) && ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) )
+ || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) )
+ {
+ /* We've either hit the input parsing restriction or the output parsing restriction.
+ * In the normal scenario, decoding a full block, it must be the last sequence,
+ * otherwise it's an error (invalid input or dimensions).
+ * In partialDecoding scenario, it's necessary to ensure there is no buffer overflow.
+ */
+ if (partialDecoding) {
+ /* Since we are partial decoding we may be in this block because of the output parsing
+ * restriction, which is not valid since the output buffer is allowed to be undersized.
+ */
+ assert(endOnInput);
+ DEBUGLOG(7, "partialDecoding: copying literals, close to input or output end")
+ DEBUGLOG(7, "partialDecoding: literal length = %u", (unsigned)length);
+ DEBUGLOG(7, "partialDecoding: remaining space in dstBuffer : %i", (int)(oend - op));
+ DEBUGLOG(7, "partialDecoding: remaining space in srcBuffer : %i", (int)(iend - ip));
+ /* Finishing in the middle of a literals segment,
+ * due to lack of input.
+ */
+ if (ip+length > iend) {
+ length = (size_t)(iend-ip);
+ cpy = op + length;
+ }
+ /* Finishing in the middle of a literals segment,
+ * due to lack of output space.
+ */
+ if (cpy > oend) {
+ cpy = oend;
+ assert(op<=oend);
+ length = (size_t)(oend-op);
+ }
+ } else {
+ /* We must be on the last sequence because of the parsing limitations so check
+ * that we exactly regenerate the original size (must be exact when !endOnInput).
+ */
+ if ((!endOnInput) && (cpy != oend)) { goto _output_error; }
+ /* We must be on the last sequence (or invalid) because of the parsing limitations
+ * so check that we exactly consume the input and don't overrun the output buffer.
+ */
+ if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) {
+ DEBUGLOG(6, "should have been last run of literals")
+ DEBUGLOG(6, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend);
+ DEBUGLOG(6, "or cpy(%p) > oend(%p)", cpy, oend);
+ goto _output_error;
+ }
+ }
+ memmove(op, ip, length); /* supports overlapping memory regions; only matters for in-place decompression scenarios */
+ ip += length;
+ op += length;
+ /* Necessarily EOF when !partialDecoding.
+ * When partialDecoding, it is EOF if we've either
+ * filled the output buffer or
+ * can't proceed with reading an offset for following match.
+ */
+ if (!partialDecoding || (cpy == oend) || (ip >= (iend-2))) {
+ break;
+ }
+ } else {
+ LZ4_wildCopy8(op, ip, cpy); /* may overwrite up to WILDCOPYLENGTH beyond cpy */
+ ip += length; op = cpy;
+ }
+
+ /* get offset */
+ offset = LZ4_readLE16(ip); ip+=2;
+ match = op - offset;
+
+ /* get matchlength */
+ length = token & ML_MASK;
+
+ _copy_match:
+ if (length == ML_MASK) {
+ variable_length_error error = ok;
+ length += read_variable_length(&ip, iend - LASTLITERALS + 1, (int)endOnInput, 0, &error);
+ if (error != ok) goto _output_error;
+ if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */
+ }
+ length += MINMATCH;
+
+#if LZ4_FAST_DEC_LOOP
+ safe_match_copy:
+#endif
+ if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */
+ /* match starting within external dictionary */
+ if ((dict==usingExtDict) && (match < lowPrefix)) {
+ if (unlikely(op+length > oend-LASTLITERALS)) {
+ if (partialDecoding) length = MIN(length, (size_t)(oend-op));
+ else goto _output_error; /* doesn't respect parsing restriction */
+ }
+
+ if (length <= (size_t)(lowPrefix-match)) {
+ /* match fits entirely within external dictionary : just copy */
+ memmove(op, dictEnd - (lowPrefix-match), length);
+ op += length;
+ } else {
+ /* match stretches into both external dictionary and current block */
+ size_t const copySize = (size_t)(lowPrefix - match);
+ size_t const restSize = length - copySize;
+ LZ4_memcpy(op, dictEnd - copySize, copySize);
+ op += copySize;
+ if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */
+ BYTE* const endOfMatch = op + restSize;
+ const BYTE* copyFrom = lowPrefix;
+ while (op < endOfMatch) *op++ = *copyFrom++;
+ } else {
+ LZ4_memcpy(op, lowPrefix, restSize);
+ op += restSize;
+ } }
+ continue;
+ }
+ assert(match >= lowPrefix);
+
+ /* copy match within block */
+ cpy = op + length;
+
+ /* partialDecoding : may end anywhere within the block */
+ assert(op<=oend);
+ if (partialDecoding && (cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {
+ size_t const mlen = MIN(length, (size_t)(oend-op));
+ const BYTE* const matchEnd = match + mlen;
+ BYTE* const copyEnd = op + mlen;
+ if (matchEnd > op) { /* overlap copy */
+ while (op < copyEnd) { *op++ = *match++; }
+ } else {
+ LZ4_memcpy(op, match, mlen);
+ }
+ op = copyEnd;
+ if (op == oend) { break; }
+ continue;
+ }
+
+ if (unlikely(offset<8)) {
+ LZ4_write32(op, 0); /* silence msan warning when offset==0 */
+ op[0] = match[0];
+ op[1] = match[1];
+ op[2] = match[2];
+ op[3] = match[3];
+ match += inc32table[offset];
+ LZ4_memcpy(op+4, match, 4);
+ match -= dec64table[offset];
+ } else {
+ LZ4_memcpy(op, match, 8);
+ match += 8;
+ }
+ op += 8;
+
+ if (unlikely(cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {
+ BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1);
+ if (cpy > oend-LASTLITERALS) { goto _output_error; } /* Error : last LASTLITERALS bytes must be literals (uncompressed) */
+ if (op < oCopyLimit) {
+ LZ4_wildCopy8(op, match, oCopyLimit);
+ match += oCopyLimit - op;
+ op = oCopyLimit;
+ }
+ while (op < cpy) { *op++ = *match++; }
+ } else {
+ LZ4_memcpy(op, match, 8);
+ if (length > 16) { LZ4_wildCopy8(op+8, match+8, cpy); }
+ }
+ op = cpy; /* wildcopy correction */
+ }
+
+ /* end of decoding */
+ if (endOnInput) {
+ DEBUGLOG(5, "decoded %i bytes", (int) (((char*)op)-dst));
+ return (int) (((char*)op)-dst); /* Nb of output bytes decoded */
+ } else {
+ return (int) (((const char*)ip)-src); /* Nb of input bytes read */
+ }
+
+ /* Overflow error detected */
+ _output_error:
+ return (int) (-(((const char*)ip)-src))-1;
+ }
+}
+
+
+/*===== Instantiate the API decoding functions. =====*/
+
+LZ4_FORCE_O2
+int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize,
+ endOnInputSize, decode_full_block, noDict,
+ (BYTE*)dest, NULL, 0);
+}
+
+LZ4_FORCE_O2
+int LZ4_decompress_safe_partial(const char* src, char* dst, int compressedSize, int targetOutputSize, int dstCapacity)
+{
+ dstCapacity = MIN(targetOutputSize, dstCapacity);
+ return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity,
+ endOnInputSize, partial_decode,
+ noDict, (BYTE*)dst, NULL, 0);
+}
+
+LZ4_FORCE_O2
+int LZ4_decompress_fast(const char* source, char* dest, int originalSize)
+{
+ return LZ4_decompress_generic(source, dest, 0, originalSize,
+ endOnOutputSize, decode_full_block, withPrefix64k,
+ (BYTE*)dest - 64 KB, NULL, 0);
+}
+
+/*===== Instantiate a few more decoding cases, used more than once. =====*/
+
+LZ4_FORCE_O2 /* Exported, an obsolete API function. */
+int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+ endOnInputSize, decode_full_block, withPrefix64k,
+ (BYTE*)dest - 64 KB, NULL, 0);
+}
+
+/* Another obsolete API function, paired with the previous one. */
+int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)
+{
+ /* LZ4_decompress_fast doesn't validate match offsets,
+ * and thus serves well with any prefixed dictionary. */
+ return LZ4_decompress_fast(source, dest, originalSize);
+}
+
+LZ4_FORCE_O2
+static int LZ4_decompress_safe_withSmallPrefix(const char* source, char* dest, int compressedSize, int maxOutputSize,
+ size_t prefixSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+ endOnInputSize, decode_full_block, noDict,
+ (BYTE*)dest-prefixSize, NULL, 0);
+}
+
+LZ4_FORCE_O2
+int LZ4_decompress_safe_forceExtDict(const char* source, char* dest,
+ int compressedSize, int maxOutputSize,
+ const void* dictStart, size_t dictSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+ endOnInputSize, decode_full_block, usingExtDict,
+ (BYTE*)dest, (const BYTE*)dictStart, dictSize);
+}
+
+LZ4_FORCE_O2
+static int LZ4_decompress_fast_extDict(const char* source, char* dest, int originalSize,
+ const void* dictStart, size_t dictSize)
+{
+ return LZ4_decompress_generic(source, dest, 0, originalSize,
+ endOnOutputSize, decode_full_block, usingExtDict,
+ (BYTE*)dest, (const BYTE*)dictStart, dictSize);
+}
+
+/* The "double dictionary" mode, for use with e.g. ring buffers: the first part
+ * of the dictionary is passed as prefix, and the second via dictStart + dictSize.
+ * These routines are used only once, in LZ4_decompress_*_continue().
+ */
+LZ4_FORCE_INLINE
+int LZ4_decompress_safe_doubleDict(const char* source, char* dest, int compressedSize, int maxOutputSize,
+ size_t prefixSize, const void* dictStart, size_t dictSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+ endOnInputSize, decode_full_block, usingExtDict,
+ (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize);
+}
+
+LZ4_FORCE_INLINE
+int LZ4_decompress_fast_doubleDict(const char* source, char* dest, int originalSize,
+ size_t prefixSize, const void* dictStart, size_t dictSize)
+{
+ return LZ4_decompress_generic(source, dest, 0, originalSize,
+ endOnOutputSize, decode_full_block, usingExtDict,
+ (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize);
+}
+
+/*===== streaming decompression functions =====*/
+
+LZ4_streamDecode_t* LZ4_createStreamDecode(void)
+{
+ LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t));
+ LZ4_STATIC_ASSERT(LZ4_STREAMDECODESIZE >= sizeof(LZ4_streamDecode_t_internal)); /* A compilation error here means LZ4_STREAMDECODESIZE is not large enough */
+ return lz4s;
+}
+
+int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)
+{
+ if (LZ4_stream == NULL) { return 0; } /* support free on NULL */
+ FREEMEM(LZ4_stream);
+ return 0;
+}
+
+/*! LZ4_setStreamDecode() :
+ * Use this function to instruct where to find the dictionary.
+ * This function is not necessary if previous data is still available where it was decoded.
+ * Loading a size of 0 is allowed (same effect as no dictionary).
+ * @return : 1 if OK, 0 if error
+ */
+int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;
+ lz4sd->prefixSize = (size_t) dictSize;
+ lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;
+ lz4sd->externalDict = NULL;
+ lz4sd->extDictSize = 0;
+ return 1;
+}
+
+/*! LZ4_decoderRingBufferSize() :
+ * when setting a ring buffer for streaming decompression (optional scenario),
+ * provides the minimum size of this ring buffer
+ * to be compatible with any source respecting maxBlockSize condition.
+ * Note : in a ring buffer scenario,
+ * blocks are presumed decompressed next to each other.
+ * When not enough space remains for next block (remainingSize < maxBlockSize),
+ * decoding resumes from beginning of ring buffer.
+ * @return : minimum ring buffer size,
+ * or 0 if there is an error (invalid maxBlockSize).
+ */
+int LZ4_decoderRingBufferSize(int maxBlockSize)
+{
+ if (maxBlockSize < 0) return 0;
+ if (maxBlockSize > LZ4_MAX_INPUT_SIZE) return 0;
+ if (maxBlockSize < 16) maxBlockSize = 16;
+ return LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize);
+}
+
+/*
+*_continue() :
+ These decoding functions allow decompression of multiple blocks in "streaming" mode.
+ Previously decoded blocks must still be available at the memory position where they were decoded.
+ If it's not possible, save the relevant part of decoded data into a safe buffer,
+ and indicate where it stands using LZ4_setStreamDecode()
+*/
+LZ4_FORCE_O2
+int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;
+ int result;
+
+ if (lz4sd->prefixSize == 0) {
+ /* The first call, no dictionary yet. */
+ assert(lz4sd->extDictSize == 0);
+ result = LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize = (size_t)result;
+ lz4sd->prefixEnd = (BYTE*)dest + result;
+ } else if (lz4sd->prefixEnd == (BYTE*)dest) {
+ /* They're rolling the current segment. */
+ if (lz4sd->prefixSize >= 64 KB - 1)
+ result = LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);
+ else if (lz4sd->extDictSize == 0)
+ result = LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize,
+ lz4sd->prefixSize);
+ else
+ result = LZ4_decompress_safe_doubleDict(source, dest, compressedSize, maxOutputSize,
+ lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize += (size_t)result;
+ lz4sd->prefixEnd += result;
+ } else {
+ /* The buffer wraps around, or they're switching to another buffer. */
+ lz4sd->extDictSize = lz4sd->prefixSize;
+ lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
+ result = LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize,
+ lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize = (size_t)result;
+ lz4sd->prefixEnd = (BYTE*)dest + result;
+ }
+
+ return result;
+}
+
+LZ4_FORCE_O2
+int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;
+ int result;
+ assert(originalSize >= 0);
+
+ if (lz4sd->prefixSize == 0) {
+ assert(lz4sd->extDictSize == 0);
+ result = LZ4_decompress_fast(source, dest, originalSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize = (size_t)originalSize;
+ lz4sd->prefixEnd = (BYTE*)dest + originalSize;
+ } else if (lz4sd->prefixEnd == (BYTE*)dest) {
+ if (lz4sd->prefixSize >= 64 KB - 1 || lz4sd->extDictSize == 0)
+ result = LZ4_decompress_fast(source, dest, originalSize);
+ else
+ result = LZ4_decompress_fast_doubleDict(source, dest, originalSize,
+ lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize += (size_t)originalSize;
+ lz4sd->prefixEnd += originalSize;
+ } else {
+ lz4sd->extDictSize = lz4sd->prefixSize;
+ lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
+ result = LZ4_decompress_fast_extDict(source, dest, originalSize,
+ lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize = (size_t)originalSize;
+ lz4sd->prefixEnd = (BYTE*)dest + originalSize;
+ }
+
+ return result;
+}
+
+
+/*
+Advanced decoding functions :
+*_usingDict() :
+ These decoding functions work the same as "_continue" ones,
+ the dictionary must be explicitly provided within parameters
+*/
+
+int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
+{
+ if (dictSize==0)
+ return LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);
+ if (dictStart+dictSize == dest) {
+ if (dictSize >= 64 KB - 1) {
+ return LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);
+ }
+ assert(dictSize >= 0);
+ return LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, (size_t)dictSize);
+ }
+ assert(dictSize >= 0);
+ return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, dictStart, (size_t)dictSize);
+}
+
+int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)
+{
+ if (dictSize==0 || dictStart+dictSize == dest)
+ return LZ4_decompress_fast(source, dest, originalSize);
+ assert(dictSize >= 0);
+ return LZ4_decompress_fast_extDict(source, dest, originalSize, dictStart, (size_t)dictSize);
+}
+
+
+/*=*************************************************
+* Obsolete Functions
+***************************************************/
+/* obsolete compression functions */
+int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+ return LZ4_compress_default(source, dest, inputSize, maxOutputSize);
+}
+int LZ4_compress(const char* src, char* dest, int srcSize)
+{
+ return LZ4_compress_default(src, dest, srcSize, LZ4_compressBound(srcSize));
+}
+int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize)
+{
+ return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1);
+}
+int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize)
+{
+ return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1);
+}
+int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int dstCapacity)
+{
+ return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, dstCapacity, 1);
+}
+int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize)
+{
+ return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1);
+}
+
+/*
+These decompression functions are deprecated and should no longer be used.
+They are only provided here for compatibility with older user programs.
+- LZ4_uncompress is totally equivalent to LZ4_decompress_fast
+- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe
+*/
+int LZ4_uncompress (const char* source, char* dest, int outputSize)
+{
+ return LZ4_decompress_fast(source, dest, outputSize);
+}
+int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize)
+{
+ return LZ4_decompress_safe(source, dest, isize, maxOutputSize);
+}
+
+/* Obsolete Streaming functions */
+
+int LZ4_sizeofStreamState(void) { return LZ4_STREAMSIZE; }
+
+int LZ4_resetStreamState(void* state, char* inputBuffer)
+{
+ (void)inputBuffer;
+ LZ4_resetStream((LZ4_stream_t*)state);
+ return 0;
+}
+
+void* LZ4_create (char* inputBuffer)
+{
+ (void)inputBuffer;
+ return LZ4_createStream();
+}
+
+char* LZ4_slideInputBuffer (void* state)
+{
+ /* avoid const char * -> char * conversion warning */
+ return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary;
+}
+
+#endif /* LZ4_COMMONDEFS_ONLY */
diff --git a/dev/ese/src/_lz4/lz4.h b/dev/ese/src/_lz4/lz4.h
new file mode 100644
index 00000000..0b11eab0
--- /dev/null
+++ b/dev/ese/src/_lz4/lz4.h
@@ -0,0 +1,774 @@
+/*
+ * LZ4 - Fast LZ compression algorithm
+ * Header File
+ * Copyright (C) 2011-2020, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - LZ4 homepage : http://www.lz4.org
+ - LZ4 source repository : https://github.com/lz4/lz4
+*/
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef LZ4_H_2983827168210
+#define LZ4_H_2983827168210
+
+/* --- Dependency --- */
+#include /* size_t */
+
+
+/**
+ Introduction
+
+ LZ4 is lossless compression algorithm, providing compression speed >500 MB/s per core,
+ scalable with multi-cores CPU. It features an extremely fast decoder, with speed in
+ multiple GB/s per core, typically reaching RAM speed limits on multi-core systems.
+
+ The LZ4 compression library provides in-memory compression and decompression functions.
+ It gives full buffer control to user.
+ Compression can be done in:
+ - a single step (described as Simple Functions)
+ - a single step, reusing a context (described in Advanced Functions)
+ - unbounded multiple steps (described as Streaming compression)
+
+ lz4.h generates and decodes LZ4-compressed blocks (doc/lz4_Block_format.md).
+ Decompressing such a compressed block requires additional metadata.
+ Exact metadata depends on exact decompression function.
+ For the typical case of LZ4_decompress_safe(),
+ metadata includes block's compressed size, and maximum bound of decompressed size.
+ Each application is free to encode and pass such metadata in whichever way it wants.
+
+ lz4.h only handle blocks, it can not generate Frames.
+
+ Blocks are different from Frames (doc/lz4_Frame_format.md).
+ Frames bundle both blocks and metadata in a specified manner.
+ Embedding metadata is required for compressed data to be self-contained and portable.
+ Frame format is delivered through a companion API, declared in lz4frame.h.
+ The `lz4` CLI can only manage frames.
+*/
+
+/*^***************************************************************
+* Export parameters
+*****************************************************************/
+/*
+* LZ4_DLL_EXPORT :
+* Enable exporting of functions when building a Windows DLL
+* LZ4LIB_VISIBILITY :
+* Control library symbols visibility.
+*/
+#ifndef LZ4LIB_VISIBILITY
+# if defined(__GNUC__) && (__GNUC__ >= 4)
+# define LZ4LIB_VISIBILITY __attribute__ ((visibility ("default")))
+# else
+# define LZ4LIB_VISIBILITY
+# endif
+#endif
+#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)
+# define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY
+#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)
+# define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
+#else
+# define LZ4LIB_API LZ4LIB_VISIBILITY
+#endif
+
+/*------ Version ------*/
+#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
+#define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */
+#define LZ4_VERSION_RELEASE 3 /* for tweaks, bug-fixes, or development */
+
+#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
+
+#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE
+#define LZ4_QUOTE(str) #str
+#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str)
+#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)
+
+LZ4LIB_API int LZ4_versionNumber (void); /**< library version number; useful to check dll version */
+LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; useful to check dll version */
+
+
+/*-************************************
+* Tuning parameter
+**************************************/
+/*!
+ * LZ4_MEMORY_USAGE :
+ * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+ * Increasing memory usage improves compression ratio.
+ * Reduced memory usage may improve speed, thanks to better cache locality.
+ * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
+ */
+#ifndef LZ4_MEMORY_USAGE
+# define LZ4_MEMORY_USAGE 14
+#endif
+
+
+/*-************************************
+* Simple Functions
+**************************************/
+/*! LZ4_compress_default() :
+ * Compresses 'srcSize' bytes from buffer 'src'
+ * into already allocated 'dst' buffer of size 'dstCapacity'.
+ * Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize).
+ * It also runs faster, so it's a recommended setting.
+ * If the function cannot compress 'src' into a more limited 'dst' budget,
+ * compression stops *immediately*, and the function result is zero.
+ * In which case, 'dst' content is undefined (invalid).
+ * srcSize : max supported value is LZ4_MAX_INPUT_SIZE.
+ * dstCapacity : size of buffer 'dst' (which must be already allocated)
+ * @return : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity)
+ * or 0 if compression fails
+ * Note : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer).
+ */
+LZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity);
+
+/*! LZ4_decompress_safe() :
+ * compressedSize : is the exact complete size of the compressed block.
+ * dstCapacity : is the size of destination buffer (which must be already allocated), presumed an upper bound of decompressed size.
+ * @return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity)
+ * If destination buffer is not large enough, decoding will stop and output an error code (negative value).
+ * If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ * Note 1 : This function is protected against malicious data packets :
+ * it will never writes outside 'dst' buffer, nor read outside 'source' buffer,
+ * even if the compressed block is maliciously modified to order the decoder to do these actions.
+ * In such case, the decoder stops immediately, and considers the compressed block malformed.
+ * Note 2 : compressedSize and dstCapacity must be provided to the function, the compressed block does not contain them.
+ * The implementation is free to send / store / derive this information in whichever way is most beneficial.
+ * If there is a need for a different format which bundles together both compressed data and its metadata, consider looking at lz4frame.h instead.
+ */
+LZ4LIB_API int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity);
+
+
+/*-************************************
+* Advanced Functions
+**************************************/
+#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
+#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
+
+/*! LZ4_compressBound() :
+ Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
+ This function is primarily useful for memory allocation purposes (destination buffer size).
+ Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
+ Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize)
+ inputSize : max supported value is LZ4_MAX_INPUT_SIZE
+ return : maximum output size in a "worst case" scenario
+ or 0, if input size is incorrect (too large or negative)
+*/
+LZ4LIB_API int LZ4_compressBound(int inputSize);
+
+/*! LZ4_compress_fast() :
+ Same as LZ4_compress_default(), but allows selection of "acceleration" factor.
+ The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
+ It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
+ An acceleration value of "1" is the same as regular LZ4_compress_default()
+ Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c).
+ Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c).
+*/
+LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
+
+
+/*! LZ4_compress_fast_extState() :
+ * Same as LZ4_compress_fast(), using an externally allocated memory space for its state.
+ * Use LZ4_sizeofState() to know how much memory must be allocated,
+ * and allocate it on 8-bytes boundaries (using `malloc()` typically).
+ * Then, provide this buffer as `void* state` to compression function.
+ */
+LZ4LIB_API int LZ4_sizeofState(void);
+LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
+
+
+/*! LZ4_compress_destSize() :
+ * Reverse the logic : compresses as much data as possible from 'src' buffer
+ * into already allocated buffer 'dst', of size >= 'targetDestSize'.
+ * This function either compresses the entire 'src' content into 'dst' if it's large enough,
+ * or fill 'dst' buffer completely with as much data as possible from 'src'.
+ * note: acceleration parameter is fixed to "default".
+ *
+ * *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'.
+ * New value is necessarily <= input value.
+ * @return : Nb bytes written into 'dst' (necessarily <= targetDestSize)
+ * or 0 if compression fails.
+ *
+ * Note : from v1.8.2 to v1.9.1, this function had a bug (fixed un v1.9.2+):
+ * the produced compressed content could, in specific circumstances,
+ * require to be decompressed into a destination buffer larger
+ * by at least 1 byte than the content to decompress.
+ * If an application uses `LZ4_compress_destSize()`,
+ * it's highly recommended to update liblz4 to v1.9.2 or better.
+ * If this can't be done or ensured,
+ * the receiving decompression function should provide
+ * a dstCapacity which is > decompressedSize, by at least 1 byte.
+ * See https://github.com/lz4/lz4/issues/859 for details
+ */
+LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize);
+
+
+/*! LZ4_decompress_safe_partial() :
+ * Decompress an LZ4 compressed block, of size 'srcSize' at position 'src',
+ * into destination buffer 'dst' of size 'dstCapacity'.
+ * Up to 'targetOutputSize' bytes will be decoded.
+ * The function stops decoding on reaching this objective.
+ * This can be useful to boost performance
+ * whenever only the beginning of a block is required.
+ *
+ * @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize)
+ * If source stream is detected malformed, function returns a negative result.
+ *
+ * Note 1 : @return can be < targetOutputSize, if compressed block contains less data.
+ *
+ * Note 2 : targetOutputSize must be <= dstCapacity
+ *
+ * Note 3 : this function effectively stops decoding on reaching targetOutputSize,
+ * so dstCapacity is kind of redundant.
+ * This is because in older versions of this function,
+ * decoding operation would still write complete sequences.
+ * Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize,
+ * it could write more bytes, though only up to dstCapacity.
+ * Some "margin" used to be required for this operation to work properly.
+ * Thankfully, this is no longer necessary.
+ * The function nonetheless keeps the same signature, in an effort to preserve API compatibility.
+ *
+ * Note 4 : If srcSize is the exact size of the block,
+ * then targetOutputSize can be any value,
+ * including larger than the block's decompressed size.
+ * The function will, at most, generate block's decompressed size.
+ *
+ * Note 5 : If srcSize is _larger_ than block's compressed size,
+ * then targetOutputSize **MUST** be <= block's decompressed size.
+ * Otherwise, *silent corruption will occur*.
+ */
+LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity);
+
+
+/*-*********************************************
+* Streaming Compression Functions
+***********************************************/
+typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */
+
+LZ4LIB_API LZ4_stream_t* LZ4_createStream(void);
+LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr);
+
+/*! LZ4_resetStream_fast() : v1.9.0+
+ * Use this to prepare an LZ4_stream_t for a new chain of dependent blocks
+ * (e.g., LZ4_compress_fast_continue()).
+ *
+ * An LZ4_stream_t must be initialized once before usage.
+ * This is automatically done when created by LZ4_createStream().
+ * However, should the LZ4_stream_t be simply declared on stack (for example),
+ * it's necessary to initialize it first, using LZ4_initStream().
+ *
+ * After init, start any new stream with LZ4_resetStream_fast().
+ * A same LZ4_stream_t can be re-used multiple times consecutively
+ * and compress multiple streams,
+ * provided that it starts each new stream with LZ4_resetStream_fast().
+ *
+ * LZ4_resetStream_fast() is much faster than LZ4_initStream(),
+ * but is not compatible with memory regions containing garbage data.
+ *
+ * Note: it's only useful to call LZ4_resetStream_fast()
+ * in the context of streaming compression.
+ * The *extState* functions perform their own resets.
+ * Invoking LZ4_resetStream_fast() before is redundant, and even counterproductive.
+ */
+LZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr);
+
+/*! LZ4_loadDict() :
+ * Use this function to reference a static dictionary into LZ4_stream_t.
+ * The dictionary must remain available during compression.
+ * LZ4_loadDict() triggers a reset, so any previous data will be forgotten.
+ * The same dictionary will have to be loaded on decompression side for successful decoding.
+ * Dictionary are useful for better compression of small data (KB range).
+ * While LZ4 accept any input as dictionary,
+ * results are generally better when using Zstandard's Dictionary Builder.
+ * Loading a size of 0 is allowed, and is the same as reset.
+ * @return : loaded dictionary size, in bytes (necessarily <= 64 KB)
+ */
+LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);
+
+/*! LZ4_compress_fast_continue() :
+ * Compress 'src' content using data from previously compressed blocks, for better compression ratio.
+ * 'dst' buffer must be already allocated.
+ * If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
+ *
+ * @return : size of compressed block
+ * or 0 if there is an error (typically, cannot fit into 'dst').
+ *
+ * Note 1 : Each invocation to LZ4_compress_fast_continue() generates a new block.
+ * Each block has precise boundaries.
+ * Each block must be decompressed separately, calling LZ4_decompress_*() with relevant metadata.
+ * It's not possible to append blocks together and expect a single invocation of LZ4_decompress_*() to decompress them together.
+ *
+ * Note 2 : The previous 64KB of source data is __assumed__ to remain present, unmodified, at same address in memory !
+ *
+ * Note 3 : When input is structured as a double-buffer, each buffer can have any size, including < 64 KB.
+ * Make sure that buffers are separated, by at least one byte.
+ * This construction ensures that each block only depends on previous block.
+ *
+ * Note 4 : If input buffer is a ring-buffer, it can have any size, including < 64 KB.
+ *
+ * Note 5 : After an error, the stream status is undefined (invalid), it can only be reset or freed.
+ */
+LZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
+
+/*! LZ4_saveDict() :
+ * If last 64KB data cannot be guaranteed to remain available at its current memory location,
+ * save it into a safer place (char* safeBuffer).
+ * This is schematically equivalent to a memcpy() followed by LZ4_loadDict(),
+ * but is much faster, because LZ4_saveDict() doesn't need to rebuild tables.
+ * @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error.
+ */
+LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int maxDictSize);
+
+
+/*-**********************************************
+* Streaming Decompression Functions
+* Bufferless synchronous API
+************************************************/
+typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* tracking context */
+
+/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() :
+ * creation / destruction of streaming decompression tracking context.
+ * A tracking context can be re-used multiple times.
+ */
+LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void);
+LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
+
+/*! LZ4_setStreamDecode() :
+ * An LZ4_streamDecode_t context can be allocated once and re-used multiple times.
+ * Use this function to start decompression of a new stream of blocks.
+ * A dictionary can optionally be set. Use NULL or size 0 for a reset order.
+ * Dictionary is presumed stable : it must remain accessible and unmodified during next decompression.
+ * @return : 1 if OK, 0 if error
+ */
+LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);
+
+/*! LZ4_decoderRingBufferSize() : v1.8.2+
+ * Note : in a ring buffer scenario (optional),
+ * blocks are presumed decompressed next to each other
+ * up to the moment there is not enough remaining space for next block (remainingSize < maxBlockSize),
+ * at which stage it resumes from beginning of ring buffer.
+ * When setting such a ring buffer for streaming decompression,
+ * provides the minimum size of this ring buffer
+ * to be compatible with any source respecting maxBlockSize condition.
+ * @return : minimum ring buffer size,
+ * or 0 if there is an error (invalid maxBlockSize).
+ */
+LZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize);
+#define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) (65536 + 14 + (maxBlockSize)) /* for static allocation; maxBlockSize presumed valid */
+
+/*! LZ4_decompress_*_continue() :
+ * These decoding functions allow decompression of consecutive blocks in "streaming" mode.
+ * A block is an unsplittable entity, it must be presented entirely to a decompression function.
+ * Decompression functions only accepts one block at a time.
+ * The last 64KB of previously decoded data *must* remain available and unmodified at the memory position where they were decoded.
+ * If less than 64KB of data has been decoded, all the data must be present.
+ *
+ * Special : if decompression side sets a ring buffer, it must respect one of the following conditions :
+ * - Decompression buffer size is _at least_ LZ4_decoderRingBufferSize(maxBlockSize).
+ * maxBlockSize is the maximum size of any single block. It can have any value > 16 bytes.
+ * In which case, encoding and decoding buffers do not need to be synchronized.
+ * Actually, data can be produced by any source compliant with LZ4 format specification, and respecting maxBlockSize.
+ * - Synchronized mode :
+ * Decompression buffer size is _exactly_ the same as compression buffer size,
+ * and follows exactly same update rule (block boundaries at same positions),
+ * and decoding function is provided with exact decompressed size of each block (exception for last block of the stream),
+ * _then_ decoding & encoding ring buffer can have any size, including small ones ( < 64 KB).
+ * - Decompression buffer is larger than encoding buffer, by a minimum of maxBlockSize more bytes.
+ * In which case, encoding and decoding buffers do not need to be synchronized,
+ * and encoding ring buffer can have any size, including small ones ( < 64 KB).
+ *
+ * Whenever these conditions are not possible,
+ * save the last 64KB of decoded data into a safe buffer where it can't be modified during decompression,
+ * then indicate where this data is saved using LZ4_setStreamDecode(), before decompressing next block.
+*/
+LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int srcSize, int dstCapacity);
+
+
+/*! LZ4_decompress_*_usingDict() :
+ * These decoding functions work the same as
+ * a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue()
+ * They are stand-alone, and don't need an LZ4_streamDecode_t structure.
+ * Dictionary is presumed stable : it must remain accessible and unmodified during decompression.
+ * Performance tip : Decompression speed can be substantially increased
+ * when dst == dictStart + dictSize.
+ */
+LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* src, char* dst, int srcSize, int dstCapcity, const char* dictStart, int dictSize);
+
+#endif /* LZ4_H_2983827168210 */
+
+
+/*^*************************************
+ * !!!!!! STATIC LINKING ONLY !!!!!!
+ ***************************************/
+
+/*-****************************************************************************
+ * Experimental section
+ *
+ * Symbols declared in this section must be considered unstable. Their
+ * signatures or semantics may change, or they may be removed altogether in the
+ * future. They are therefore only safe to depend on when the caller is
+ * statically linked against the library.
+ *
+ * To protect against unsafe usage, not only are the declarations guarded,
+ * the definitions are hidden by default
+ * when building LZ4 as a shared/dynamic library.
+ *
+ * In order to access these declarations,
+ * define LZ4_STATIC_LINKING_ONLY in your application
+ * before including LZ4's headers.
+ *
+ * In order to make their implementations accessible dynamically, you must
+ * define LZ4_PUBLISH_STATIC_FUNCTIONS when building the LZ4 library.
+ ******************************************************************************/
+
+#ifdef LZ4_STATIC_LINKING_ONLY
+
+#ifndef LZ4_STATIC_3504398509
+#define LZ4_STATIC_3504398509
+
+#ifdef LZ4_PUBLISH_STATIC_FUNCTIONS
+#define LZ4LIB_STATIC_API LZ4LIB_API
+#else
+#define LZ4LIB_STATIC_API
+#endif
+
+
+/*! LZ4_compress_fast_extState_fastReset() :
+ * A variant of LZ4_compress_fast_extState().
+ *
+ * Using this variant avoids an expensive initialization step.
+ * It is only safe to call if the state buffer is known to be correctly initialized already
+ * (see above comment on LZ4_resetStream_fast() for a definition of "correctly initialized").
+ * From a high level, the difference is that
+ * this function initializes the provided state with a call to something like LZ4_resetStream_fast()
+ * while LZ4_compress_fast_extState() starts with a call to LZ4_resetStream().
+ */
+LZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
+
+/*! LZ4_attach_dictionary() :
+ * This is an experimental API that allows
+ * efficient use of a static dictionary many times.
+ *
+ * Rather than re-loading the dictionary buffer into a working context before
+ * each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a
+ * working LZ4_stream_t, this function introduces a no-copy setup mechanism,
+ * in which the working stream references the dictionary stream in-place.
+ *
+ * Several assumptions are made about the state of the dictionary stream.
+ * Currently, only streams which have been prepared by LZ4_loadDict() should
+ * be expected to work.
+ *
+ * Alternatively, the provided dictionaryStream may be NULL,
+ * in which case any existing dictionary stream is unset.
+ *
+ * If a dictionary is provided, it replaces any pre-existing stream history.
+ * The dictionary contents are the only history that can be referenced and
+ * logically immediately precede the data compressed in the first subsequent
+ * compression call.
+ *
+ * The dictionary will only remain attached to the working stream through the
+ * first compression call, at the end of which it is cleared. The dictionary
+ * stream (and source buffer) must remain in-place / accessible / unchanged
+ * through the completion of the first compression call on the stream.
+ */
+LZ4LIB_STATIC_API void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream);
+
+
+/*! In-place compression and decompression
+ *
+ * It's possible to have input and output sharing the same buffer,
+ * for highly constrained memory environments.
+ * In both cases, it requires input to lay at the end of the buffer,
+ * and decompression to start at beginning of the buffer.
+ * Buffer size must feature some margin, hence be larger than final size.
+ *
+ * |<------------------------buffer--------------------------------->|
+ * |<-----------compressed data--------->|
+ * |<-----------decompressed size------------------>|
+ * |<----margin---->|
+ *
+ * This technique is more useful for decompression,
+ * since decompressed size is typically larger,
+ * and margin is short.
+ *
+ * In-place decompression will work inside any buffer
+ * which size is >= LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize).
+ * This presumes that decompressedSize > compressedSize.
+ * Otherwise, it means compression actually expanded data,
+ * and it would be more efficient to store such data with a flag indicating it's not compressed.
+ * This can happen when data is not compressible (already compressed, or encrypted).
+ *
+ * For in-place compression, margin is larger, as it must be able to cope with both
+ * history preservation, requiring input data to remain unmodified up to LZ4_DISTANCE_MAX,
+ * and data expansion, which can happen when input is not compressible.
+ * As a consequence, buffer size requirements are much higher,
+ * and memory savings offered by in-place compression are more limited.
+ *
+ * There are ways to limit this cost for compression :
+ * - Reduce history size, by modifying LZ4_DISTANCE_MAX.
+ * Note that it is a compile-time constant, so all compressions will apply this limit.
+ * Lower values will reduce compression ratio, except when input_size < LZ4_DISTANCE_MAX,
+ * so it's a reasonable trick when inputs are known to be small.
+ * - Require the compressor to deliver a "maximum compressed size".
+ * This is the `dstCapacity` parameter in `LZ4_compress*()`.
+ * When this size is < LZ4_COMPRESSBOUND(inputSize), then compression can fail,
+ * in which case, the return code will be 0 (zero).
+ * The caller must be ready for these cases to happen,
+ * and typically design a backup scheme to send data uncompressed.
+ * The combination of both techniques can significantly reduce
+ * the amount of margin required for in-place compression.
+ *
+ * In-place compression can work in any buffer
+ * which size is >= (maxCompressedSize)
+ * with maxCompressedSize == LZ4_COMPRESSBOUND(srcSize) for guaranteed compression success.
+ * LZ4_COMPRESS_INPLACE_BUFFER_SIZE() depends on both maxCompressedSize and LZ4_DISTANCE_MAX,
+ * so it's possible to reduce memory requirements by playing with them.
+ */
+
+#define LZ4_DECOMPRESS_INPLACE_MARGIN(compressedSize) (((compressedSize) >> 8) + 32)
+#define LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize) ((decompressedSize) + LZ4_DECOMPRESS_INPLACE_MARGIN(decompressedSize)) /**< note: presumes that compressedSize < decompressedSize. note2: margin is overestimated a bit, since it could use compressedSize instead */
+
+#ifndef LZ4_DISTANCE_MAX /* history window size; can be user-defined at compile time */
+# define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */
+#endif
+
+#define LZ4_COMPRESS_INPLACE_MARGIN (LZ4_DISTANCE_MAX + 32) /* LZ4_DISTANCE_MAX can be safely replaced by srcSize when it's smaller */
+#define LZ4_COMPRESS_INPLACE_BUFFER_SIZE(maxCompressedSize) ((maxCompressedSize) + LZ4_COMPRESS_INPLACE_MARGIN) /**< maxCompressedSize is generally LZ4_COMPRESSBOUND(inputSize), but can be set to any lower value, with the risk that compression can fail (return code 0(zero)) */
+
+#endif /* LZ4_STATIC_3504398509 */
+#endif /* LZ4_STATIC_LINKING_ONLY */
+
+
+
+#ifndef LZ4_H_98237428734687
+#define LZ4_H_98237428734687
+
+/*-************************************************************
+ * Private Definitions
+ **************************************************************
+ * Do not use these definitions directly.
+ * They are only exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`.
+ * Accessing members will expose user code to API and/or ABI break in future versions of the library.
+ **************************************************************/
+#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2)
+#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
+#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
+
+#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+# include
+ typedef int8_t LZ4_i8;
+ typedef uint8_t LZ4_byte;
+ typedef uint16_t LZ4_u16;
+ typedef uint32_t LZ4_u32;
+#else
+ typedef signed char LZ4_i8;
+ typedef unsigned char LZ4_byte;
+ typedef unsigned short LZ4_u16;
+ typedef unsigned int LZ4_u32;
+#endif
+
+typedef struct LZ4_stream_t_internal LZ4_stream_t_internal;
+struct LZ4_stream_t_internal {
+ LZ4_u32 hashTable[LZ4_HASH_SIZE_U32];
+ LZ4_u32 currentOffset;
+ LZ4_u32 tableType;
+ const LZ4_byte* dictionary;
+ const LZ4_stream_t_internal* dictCtx;
+ LZ4_u32 dictSize;
+};
+
+typedef struct {
+ const LZ4_byte* externalDict;
+ size_t extDictSize;
+ const LZ4_byte* prefixEnd;
+ size_t prefixSize;
+} LZ4_streamDecode_t_internal;
+
+
+/*! LZ4_stream_t :
+ * Do not use below internal definitions directly !
+ * Declare or allocate an LZ4_stream_t instead.
+ * LZ4_stream_t can also be created using LZ4_createStream(), which is recommended.
+ * The structure definition can be convenient for static allocation
+ * (on stack, or as part of larger structure).
+ * Init this structure with LZ4_initStream() before first use.
+ * note : only use this definition in association with static linking !
+ * this definition is not API/ABI safe, and may change in future versions.
+ */
+#define LZ4_STREAMSIZE 16416 /* static size, for inter-version compatibility */
+#define LZ4_STREAMSIZE_VOIDP (LZ4_STREAMSIZE / sizeof(void*))
+union LZ4_stream_u {
+ void* table[LZ4_STREAMSIZE_VOIDP];
+ LZ4_stream_t_internal internal_donotuse;
+}; /* previously typedef'd to LZ4_stream_t */
+
+
+/*! LZ4_initStream() : v1.9.0+
+ * An LZ4_stream_t structure must be initialized at least once.
+ * This is automatically done when invoking LZ4_createStream(),
+ * but it's not when the structure is simply declared on stack (for example).
+ *
+ * Use LZ4_initStream() to properly initialize a newly declared LZ4_stream_t.
+ * It can also initialize any arbitrary buffer of sufficient size,
+ * and will @return a pointer of proper type upon initialization.
+ *
+ * Note : initialization fails if size and alignment conditions are not respected.
+ * In which case, the function will @return NULL.
+ * Note2: An LZ4_stream_t structure guarantees correct alignment and size.
+ * Note3: Before v1.9.0, use LZ4_resetStream() instead
+ */
+LZ4LIB_API LZ4_stream_t* LZ4_initStream (void* buffer, size_t size);
+
+
+/*! LZ4_streamDecode_t :
+ * information structure to track an LZ4 stream during decompression.
+ * init this structure using LZ4_setStreamDecode() before first use.
+ * note : only use in association with static linking !
+ * this definition is not API/ABI safe,
+ * and may change in a future version !
+ */
+#define LZ4_STREAMDECODESIZE_U64 (4 + ((sizeof(void*)==16) ? 2 : 0) /*AS-400*/ )
+#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
+union LZ4_streamDecode_u {
+ unsigned long long table[LZ4_STREAMDECODESIZE_U64];
+ LZ4_streamDecode_t_internal internal_donotuse;
+} ; /* previously typedef'd to LZ4_streamDecode_t */
+
+
+
+/*-************************************
+* Obsolete Functions
+**************************************/
+
+/*! Deprecation warnings
+ *
+ * Deprecated functions make the compiler generate a warning when invoked.
+ * This is meant to invite users to update their source code.
+ * Should deprecation warnings be a problem, it is generally possible to disable them,
+ * typically with -Wno-deprecated-declarations for gcc
+ * or _CRT_SECURE_NO_WARNINGS in Visual.
+ *
+ * Another method is to define LZ4_DISABLE_DEPRECATE_WARNINGS
+ * before including the header file.
+ */
+#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS
+# define LZ4_DEPRECATED(message) /* disable deprecation warnings */
+#else
+# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
+# define LZ4_DEPRECATED(message) [[deprecated(message)]]
+# elif defined(_MSC_VER)
+# define LZ4_DEPRECATED(message) __declspec(deprecated(message))
+# elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45))
+# define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
+# elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31)
+# define LZ4_DEPRECATED(message) __attribute__((deprecated))
+# else
+# pragma message("WARNING: LZ4_DEPRECATED needs custom implementation for this compiler")
+# define LZ4_DEPRECATED(message) /* disabled */
+# endif
+#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */
+
+/*! Obsolete compression functions (since v1.7.3) */
+LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress (const char* src, char* dest, int srcSize);
+LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress_limitedOutput (const char* src, char* dest, int srcSize, int maxOutputSize);
+LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize);
+LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
+LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
+LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/*! Obsolete decompression functions (since v1.8.0) */
+LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize);
+LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize);
+
+/* Obsolete streaming functions (since v1.7.0)
+ * degraded functionality; do not use!
+ *
+ * In order to perform streaming compression, these functions depended on data
+ * that is no longer tracked in the state. They have been preserved as well as
+ * possible: using them will still produce a correct output. However, they don't
+ * actually retain any history between compression calls. The compression ratio
+ * achieved will therefore be no better than compressing each chunk
+ * independently.
+ */
+LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API void* LZ4_create (char* inputBuffer);
+LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API int LZ4_sizeofStreamState(void);
+LZ4_DEPRECATED("Use LZ4_resetStream() instead") LZ4LIB_API int LZ4_resetStreamState(void* state, char* inputBuffer);
+LZ4_DEPRECATED("Use LZ4_saveDict() instead") LZ4LIB_API char* LZ4_slideInputBuffer (void* state);
+
+/*! Obsolete streaming decoding functions (since v1.7.0) */
+LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);
+LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);
+
+/*! Obsolete LZ4_decompress_fast variants (since v1.9.0) :
+ * These functions used to be faster than LZ4_decompress_safe(),
+ * but this is no longer the case. They are now slower.
+ * This is because LZ4_decompress_fast() doesn't know the input size,
+ * and therefore must progress more cautiously into the input buffer to not read beyond the end of block.
+ * On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability.
+ * As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated.
+ *
+ * The last remaining LZ4_decompress_fast() specificity is that
+ * it can decompress a block without knowing its compressed size.
+ * Such functionality can be achieved in a more secure manner
+ * by employing LZ4_decompress_safe_partial().
+ *
+ * Parameters:
+ * originalSize : is the uncompressed size to regenerate.
+ * `dst` must be already allocated, its size must be >= 'originalSize' bytes.
+ * @return : number of bytes read from source buffer (== compressed size).
+ * The function expects to finish at block's end exactly.
+ * If the source stream is detected malformed, the function stops decoding and returns a negative result.
+ * note : LZ4_decompress_fast*() requires originalSize. Thanks to this information, it never writes past the output buffer.
+ * However, since it doesn't know its 'src' size, it may read an unknown amount of input, past input buffer bounds.
+ * Also, since match offsets are not validated, match reads from 'src' may underflow too.
+ * These issues never happen if input (compressed) data is correct.
+ * But they may happen if input data is invalid (error or intentional tampering).
+ * As a consequence, use these functions in trusted environments with trusted data **only**.
+ */
+LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead")
+LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize);
+LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead")
+LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize);
+LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead")
+LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize);
+
+/*! LZ4_resetStream() :
+ * An LZ4_stream_t structure must be initialized at least once.
+ * This is done with LZ4_initStream(), or LZ4_resetStream().
+ * Consider switching to LZ4_initStream(),
+ * invoking LZ4_resetStream() will trigger deprecation warnings in the future.
+ */
+LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr);
+
+
+#endif /* LZ4_H_98237428734687 */
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/dev/ese/src/_perfctrs/perfdata.pl b/dev/ese/src/_perfctrs/perfdata.pl
index af37e74d..fa08c2f8 100644
--- a/dev/ese/src/_perfctrs/perfdata.pl
+++ b/dev/ese/src/_perfctrs/perfdata.pl
@@ -376,13 +376,6 @@
#include
-#pragma prefast(push)
-#pragma prefast(disable:26006, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:26007, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28718, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28726, "Dont bother us with tchar, someone else owns that.")
-#include
-#pragma prefast(pop)
#include
#include
@@ -458,8 +451,7 @@
#else
#include
-#include
-
+
#include "perfmon.hxx"
#pragma pack(4)
@@ -639,7 +631,7 @@ sub PopulatePerfDataTemplate
};
// These two objects should be the same.
-C_ASSERT( sizeof( PerfDataTemplateReadOnly ) == sizeof( PerfDataTemplateReadWrite ) );
+static_assert( sizeof( PerfDataTemplateReadOnly ) == sizeof( PerfDataTemplateReadWrite ) );
EOF9
diff --git a/dev/ese/src/_res/jetmsg.mc b/dev/ese/src/_res/jetmsg.mc
index 835eec8a..31e0d394 100644
--- a/dev/ese/src/_res/jetmsg.mc
+++ b/dev/ese/src/_res/jetmsg.mc
@@ -215,6 +215,17 @@ Language=English
%1 (%2) %3The specific ESE configuration store is locked in a read inhibit state, clear the %1 registry value to enable ESE to continue and utilize the config store.
.
+MessageId=109
+SymbolicName=START_INSTANCE_FAILED_ID
+Language=English
+%1 (%2) %3The database engine failed to start instance (%4) due to error %5. (Time=%6 seconds)
+%n
+Failure Details:%n
+Mode: %7%n
+Fail Address: %8%n
+Publishing: %9%n
+.
+
;// You are almost assuredly not adding in the right place?
@@ -1695,6 +1706,12 @@ Language=English
%1 (%2) %3Database %4: Page %5 in a B-Tree (ObjectId: %6) failed verfication due to page FDP delete flag mismatch at log position %7. The remote page FDP delete flag persisted to the log record was %8 but the actual page FDP delete flag was %9. This problem is likely due to revert of the database gone wrong. Please investigate the database revert operations performed on the database.%n
.
+MessageId=571
+SymbolicName=DB_PAGE_FDP_REDELETE_EXPECTED_ID
+Language=English
+%1 (%2) %3Database %4: Page %5 failed verification due to being reverted using revert snapshot without having page fdp delete flag set, but the log record at log position %6 expected the page to have the flag set (log position commit before revert - %7). This problem is likely due to revert of the database gone wrong. Please investigate the database revert operations performed on the database.%n
+.
+
;// !!! ARE YOU SURE you're adding this in the right place !!! ???
@@ -2507,11 +2524,16 @@ Pages shelved: %24 page(s).%n
Pages unleaked: %25 page(s).%n
Return code: %17%n
Stop reason: %18%n
+Available space below target: %34 bytes (%35 page(s)).%n
+Small-space trees converted: %27 tree(s).%n
+Root pages moved (regular, space): %28 page(s), %29 page(s).%n
+Strictly-internal pages moved (regular, space): %30 page(s), %31 page(s).%n
+Strictly-leaf pages moved (regular, space): %32 page(s), %33 page(s).%n
Total time: %5 minute(s) and %6 second(s).%n
Pct. time in extent maintenance: %19%%%n
Pct. time in file truncation: %20%%%n
Pct. time in page categorization: %21%%%n
-Pct. time in data move: %22%%%n
+Pct. time in page processing: %22%% (%26%% in page moves)%n
Pct. remaining time: %23%%%n
.
@@ -2528,11 +2550,16 @@ Pages shelved: %24 page(s).%n
Pages unleaked: %25 page(s).%n
Error code: %17%n
Stop reason: %18%n
+Available space below target: %34 bytes (%35 page(s)).%n
+Small-space trees converted: %27 tree(s).%n
+Root pages moved (regular, space): %28 page(s), %29 page(s).%n
+Strictly-internal pages moved (regular, space): %30 page(s), %31 page(s).%n
+Strictly-leaf pages moved (regular, space): %32 page(s), %33 page(s).%n
Total time: %5 minute(s) and %6 second(s).%n
Pct. time in extent maintenance: %19%%%n
Pct. time in file truncation: %20%%%n
Pct. time in page categorization: %21%%%n
-Pct. time in data move: %22%%%n
+Pct. time in page processing: %22%% (%26%% in page moves)%n
Pct. remaining time: %23%%%n
.
@@ -2622,6 +2649,7 @@ Number of uncached primary objects: %38%n
Correction applied to space owned by primary objects: %46 page(s) (%47 bytes, %48%%).%n
Enumeration conflicts resolved successfully: %49%n
Enumeration conflicts not resolved successfully: %50%n
+Time spent resolving conflicts: %51 seconds(s).%n
Performance: %39 page(s) read, %40 page(s) preread, %41 page(s) referenced, %42 page(s) dirtied, %43 page(s) re-dirtied.%n
Duration: %44 minute(s) and %45 second(s).%n
.
diff --git a/dev/ese/src/_xpress10/xpress10corsica.cxx b/dev/ese/src/_xpress10/xpress10corsica.cxx
index 9f726acf..24a2f816 100644
--- a/dev/ese/src/_xpress10/xpress10corsica.cxx
+++ b/dev/ese/src/_xpress10/xpress10corsica.cxx
@@ -9,13 +9,6 @@
#include
#include
#include
-#pragma prefast(push)
-#pragma prefast(disable:26006, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:26007, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28718, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28726, "Dont bother us with tchar, someone else owns that.")
-#include
-#pragma prefast(pop)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
diff --git a/dev/ese/src/_xpress10/xpress10sw.cxx b/dev/ese/src/_xpress10/xpress10sw.cxx
index cc3a909f..b1671d76 100644
--- a/dev/ese/src/_xpress10/xpress10sw.cxx
+++ b/dev/ese/src/_xpress10/xpress10sw.cxx
@@ -9,13 +9,6 @@
#include
#include
#include
-#pragma prefast(push)
-#pragma prefast(disable:26006, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:26007, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28718, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28726, "Dont bother us with tchar, someone else owns that.")
-#include
-#pragma prefast(pop)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
diff --git a/dev/ese/src/checksum/checksumstd.hxx b/dev/ese/src/checksum/checksumstd.hxx
index d215b473..639aade3 100644
--- a/dev/ese/src/checksum/checksumstd.hxx
+++ b/dev/ese/src/checksum/checksumstd.hxx
@@ -5,13 +5,6 @@
#include
#include
-#pragma prefast(push)
-#pragma prefast(disable:26006, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:26007, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28718, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28726, "Dont bother us with tchar, someone else owns that.")
-#include
-#pragma prefast(pop)
#include
#include
#include
diff --git a/dev/ese/src/ese/CMakeLists.txt b/dev/ese/src/ese/CMakeLists.txt
index 006be537..60f8d7c6 100644
--- a/dev/ese/src/ese/CMakeLists.txt
+++ b/dev/ese/src/ese/CMakeLists.txt
@@ -23,6 +23,7 @@ add_compile_definitions(
set(ESE_SOURCES
${ESE_DEV}/src/ese/backup.cxx
+ ${ESE_DEV}/src/ese/bbtbuff.cxx
${ESE_DEV}/src/ese/bf.cxx
${ESE_DEV}/src/ese/bt.cxx
${ESE_DEV}/src/ese/callback.cxx
@@ -88,6 +89,7 @@ set(ESE_LIBRARIES
dht
sync
_errstr
+ _lz4
_xpress
_perfctrs
_log
diff --git a/dev/ese/src/ese/_log/log.cxx b/dev/ese/src/ese/_log/log.cxx
index 127ed39d..3f0f20ea 100644
--- a/dev/ese/src/ese/_log/log.cxx
+++ b/dev/ese/src/ese/_log/log.cxx
@@ -2567,6 +2567,7 @@ ERR LOG::ErrLGReadCheckpoint( _In_ PCWSTR wszCheckpointFile, CHECKPOINT *pcheckp
m_pinst,
m_pinst->m_pfsapi,
wszCheckpointFile,
+ JET_filetypeCheckpoint,
(BYTE*)pcheckpoint,
sizeof(CHECKPOINT),
-1,
diff --git a/dev/ese/src/ese/_log/logdump.cxx b/dev/ese/src/ese/_log/logdump.cxx
index 16d6c632..9ad31064 100644
--- a/dev/ese/src/ese/_log/logdump.cxx
+++ b/dev/ese/src/ese/_log/logdump.cxx
@@ -537,13 +537,13 @@ ERR ErrDUMPLog( INST *pinst, _In_ PCWSTR wszLog, const LONG lgenStart, const LON
const ULONG cchLogPath = LOSStrLengthW( wszLog );
const WCHAR * wszLogExt = NULL;
ULONG cLogDigits = 0;
- CWPRINTFFILE cpfCsvOut( wszCsvDataFile );
+ CPRINTFFILE cpfCsvOutW( wszCsvDataFile, CPRINTFFILE::FILEENCODING::UTF16 );
DIRLOGGENERATIONINFO dirloginfo = { 0 };
LONG lgenStartSanitised = 0;
LONG lgenEndSanitised = 0;
logdumpOp.m_opts = 0;
- Assert( logdumpOp.m_pcwpfCsvOut == NULL );
+ Assert( logdumpOp.m_pcpfCsvOutW == NULL );
if ( cchLogPath >= IFileSystemAPI::cchPathMax )
{
@@ -570,14 +570,14 @@ ERR ErrDUMPLog( INST *pinst, _In_ PCWSTR wszLog, const LONG lgenStart, const LON
if ( grbit & JET_bitDBUtilOptionDumpLogInfoCSV )
{
Assert( wszCsvDataFile ); // otherwise we won't be printing to any file.
- logdumpOp.m_pcwpfCsvOut = &cpfCsvOut;
+ logdumpOp.m_pcpfCsvOutW = &cpfCsvOutW;
DUMPPrintF( "\n Csv file: %ws\n", wszCsvDataFile );
- if (JET_errSuccess != logdumpOp.m_pcwpfCsvOut->m_errLast)
+ if (JET_errSuccess != logdumpOp.m_pcpfCsvOutW->m_errLast)
{
DUMPPrintF( "\n Cannot open csv file (%ws). Error %d.\n",
- wszCsvDataFile, logdumpOp.m_pcwpfCsvOut->m_errLast);
- Call( ErrERRCheck( logdumpOp.m_pcwpfCsvOut->m_errLast ) );
+ wszCsvDataFile, logdumpOp.m_pcpfCsvOutW->m_errLast);
+ Call( ErrERRCheck( logdumpOp.m_pcpfCsvOutW->m_errLast ) );
}
}
else if ( grbit & JET_bitDBUtilOptionDumpVerboseLevel1 )
@@ -760,12 +760,12 @@ ERR ErrDUMPLog( INST *pinst, _In_ PCWSTR wszLog, const LONG lgenStart, const LON
// for checksum mode, eseutil will generate the whitespace on error
}
- if (logdumpOp.m_pcwpfCsvOut
- && (JET_errSuccess != logdumpOp.m_pcwpfCsvOut->m_errLast))
+ if (logdumpOp.m_pcpfCsvOutW
+ && (JET_errSuccess != logdumpOp.m_pcpfCsvOutW->m_errLast))
{
DUMPPrintF( "\n Cannot write csv file (%ws). Error %d.\n",
- wszCsvDataFile, logdumpOp.m_pcwpfCsvOut->m_errLast);
- Call( ErrERRCheck( logdumpOp.m_pcwpfCsvOut->m_errLast ) );
+ wszCsvDataFile, logdumpOp.m_pcpfCsvOutW->m_errLast);
+ Call( ErrERRCheck( logdumpOp.m_pcpfCsvOutW->m_errLast ) );
}
}
else
@@ -789,7 +789,7 @@ ERR ErrDUMPLog( INST *pinst, _In_ PCWSTR wszLog, const LONG lgenStart, const LON
else if ( grbit & JET_bitDBUtilOptionDumpLogInfoCSV )
{
Assert( wszCsvDataFile ); // otherwise we won't be printing to any file.
- logdumpOp.m_pcwpfCsvOut = &cpfCsvOut;
+ logdumpOp.m_pcpfCsvOutW = &cpfCsvOutW;
}
else
{
@@ -822,14 +822,14 @@ ERR ErrDUMPLog( INST *pinst, _In_ PCWSTR wszLog, const LONG lgenStart, const LON
{
DUMPPrintF( " Base name: %ws\n", SzParam( pinst, JET_paramBaseName ) );
DUMPPrintF( " Log file: %ws", wszLog );
- if (logdumpOp.m_pcwpfCsvOut)
+ if (logdumpOp.m_pcpfCsvOutW)
{
DUMPPrintF( "\n Csv file: %ws", wszCsvDataFile );
- if (JET_errSuccess != logdumpOp.m_pcwpfCsvOut->m_errLast)
+ if (JET_errSuccess != logdumpOp.m_pcpfCsvOutW->m_errLast)
{
DUMPPrintF( "\n Cannot open csv file (%ws). Error %d.\n",
- wszCsvDataFile, logdumpOp.m_pcwpfCsvOut->m_errLast);
- Call( ErrERRCheck( logdumpOp.m_pcwpfCsvOut->m_errLast ) );
+ wszCsvDataFile, logdumpOp.m_pcpfCsvOutW->m_errLast);
+ Call( ErrERRCheck( logdumpOp.m_pcpfCsvOutW->m_errLast ) );
}
}
}
@@ -838,12 +838,12 @@ ERR ErrDUMPLog( INST *pinst, _In_ PCWSTR wszLog, const LONG lgenStart, const LON
if ( !logdumpOp.m_fVerifyOnly )
{
- if (logdumpOp.m_pcwpfCsvOut
- && (JET_errSuccess != logdumpOp.m_pcwpfCsvOut->m_errLast))
+ if (logdumpOp.m_pcpfCsvOutW
+ && (JET_errSuccess != logdumpOp.m_pcpfCsvOutW->m_errLast))
{
DUMPPrintF( "\n Cannot write csv file (%ws). Error %d.\n",
- wszCsvDataFile, logdumpOp.m_pcwpfCsvOut->m_errLast);
- Call( ErrERRCheck( logdumpOp.m_pcwpfCsvOut->m_errLast ) );
+ wszCsvDataFile, logdumpOp.m_pcpfCsvOutW->m_errLast);
+ Call( ErrERRCheck( logdumpOp.m_pcpfCsvOutW->m_errLast ) );
}
DUMPPrintF( "\n" );
}
@@ -854,7 +854,7 @@ ERR ErrDUMPLog( INST *pinst, _In_ PCWSTR wszLog, const LONG lgenStart, const LON
}
HandleError:
- logdumpOp.m_pcwpfCsvOut = NULL; // stack var will be freed ...
+ logdumpOp.m_pcpfCsvOutW = NULL; // stack var will be freed ...
if ( NULL != plgfilehdr )
{
OSMemoryPageFree( plgfilehdr );
@@ -884,7 +884,7 @@ ERR LOG::ErrLGIDumpOneAttachment( const ATTACHINFO * const pattachinfo, const LO
Call( wszDbName.ErrSet( (CHAR*)(pattachinfo->szNames) ) );
}
- if ( NULL == plogdumpOp->m_pcwpfCsvOut )
+ if ( NULL == plogdumpOp->m_pcpfCsvOutW )
{
DUMPPrintF( " %d %ws%ws\n",
pattachinfo->Dbid(), (WCHAR *)wszDbName, pattachinfo->FSparseEnabledFile() ? L" (sparse)" : L"" );
@@ -900,7 +900,7 @@ ERR LOG::ErrLGIDumpOneAttachment( const ATTACHINFO * const pattachinfo, const LO
}
const size_t cchHexDumped = 3 * sizeof( pattachinfo->signDb );
rgwchSignBuf[ cchHexDumped ] = L'\0';
- (*(plogdumpOp->m_pcwpfCsvOut))( L"%s, %d, \"%s\", %s\r\n", wszLogHeaderAttachInfo, pattachinfo->Dbid(), (WCHAR *)wszDbName, rgwchSignBuf );
+ (*(plogdumpOp->m_pcpfCsvOutW))( L"%s, %d, \"%s\", %s\r\n", wszLogHeaderAttachInfo, pattachinfo->Dbid(), (WCHAR *)wszDbName, rgwchSignBuf );
}
HandleError:
@@ -1201,7 +1201,7 @@ ERR LOG::ErrLGDumpLog( IFileAPI *const pfapi, LOGDUMP_OP * const plogdumpOp, LGF
WCHAR const * wszLogHeaderGeneralInfo = L"LHGI";
- if( plogdumpOp->m_pcwpfCsvOut )
+ if( plogdumpOp->m_pcpfCsvOutW )
{
CHAR szLogSig[128]; // plenty of space
WCHAR wszLogCreate[128]; // plenty of space
@@ -1228,7 +1228,7 @@ ERR LOG::ErrLGDumpLog( IFileAPI *const pfapi, LOGDUMP_OP * const plogdumpOp, LGF
(SHORT) m_pLogStream->GetCurrentFileHdr()->lgfilehdr.tmPrevGen.bSeconds,
(SHORT) m_pLogStream->GetCurrentFileHdr()->lgfilehdr.tmPrevGen.Milliseconds());
- (*(plogdumpOp->m_pcwpfCsvOut))(L"%ws, %hs, %08.08X, %08.08X, %ws, %ws, %d.%d.%d.%d, %ws, %d\r\n",
+ (*(plogdumpOp->m_pcpfCsvOutW))(L"%ws, %hs, %08.08X, %08.08X, %ws, %ws, %d.%d.%d.%d, %ws, %d\r\n",
wszLogHeaderGeneralInfo, szLogSig, (ULONG)m_pLogStream->GetCurrentFileGen(),
(ULONG)m_pLogStream->GetCurrentFileHdr()->lgfilehdr.le_ulChecksum,
wszLogCreate, wszPrevLogCreate,
@@ -1303,7 +1303,7 @@ ERR LOG::ErrLGDumpLog( IFileAPI *const pfapi, LOGDUMP_OP * const plogdumpOp, LGF
(USHORT)m_pLogStream->GetCurrentFileHdr()->lgfilehdr.le_lgposCheckpoint.le_ib );
}
- if ( fPrint || plogdumpOp->m_pcwpfCsvOut )
+ if ( fPrint || plogdumpOp->m_pcpfCsvOutW )
{
err = ErrLGIDumpAttachments( plogdumpOp );
if ( err < 0 )
@@ -1432,13 +1432,13 @@ ERR LOG::ErrLGDumpLog( IFileAPI *const pfapi, LOGDUMP_OP * const plogdumpOp, LGF
}
}
- if( plogdumpOp->m_pcwpfCsvOut )
+ if( plogdumpOp->m_pcpfCsvOutW )
{
LGPOS lgpos;
m_pLogReadBuffer->GetLgposOfPbNext(&lgpos);
Assert( lgpos.lGeneration == LONG(m_pLogStream->GetCurrentFileGen()) );
lgpos.lGeneration = LONG(m_pLogStream->GetCurrentFileGen());
- Call( ErrLrToLogCsvSimple( plogdumpOp->m_pcwpfCsvOut, lgpos, plr, this ) );
+ Call( ErrLrToLogCsvSimple( plogdumpOp->m_pcpfCsvOutW, lgpos, plr, this ) );
}
logRecPosCurr++;
@@ -1453,17 +1453,17 @@ ERR LOG::ErrLGDumpLog( IFileAPI *const pfapi, LOGDUMP_OP * const plogdumpOp, LGF
Call( err );
CallS( err );
- if (plogdumpOp->m_pcwpfCsvOut)
+ if (plogdumpOp->m_pcpfCsvOutW)
{
// SOMEONE doesn't want the added dev/test cost of parsing LTCL along with LTEL and .
// So, a csv dump will end with LTEL (good log) or (bad log or problems with csv file).
// SOMEONE believes LTCL is needed because the corruption may have occcured after
// the DB was updated with info past the corruption in the log. But SOMEONE's current design
// doesn't need this refinement and so I am disabling LTCL at his request.
- // (*plogdumpOp->m_pcwpfCsvOut)((fCorrupt) ? szLogTrailerCorruptLog : szLogTrailerEndOfLog);
+ // (*plogdumpOp->m_pcpfCsvOutW)((fCorrupt) ? szLogTrailerCorruptLog : szLogTrailerEndOfLog);
if (!fCorrupt)
{
- (*plogdumpOp->m_pcwpfCsvOut)(szLogTrailerEndOfLog);
+ (*plogdumpOp->m_pcpfCsvOutW)(szLogTrailerEndOfLog);
}
}
// verbose dump
diff --git a/dev/ese/src/ese/_log/logread.cxx b/dev/ese/src/ese/_log/logread.cxx
index edd61c37..1a4103c8 100644
--- a/dev/ese/src/ese/_log/logread.cxx
+++ b/dev/ese/src/ese/_log/logread.cxx
@@ -623,8 +623,7 @@ VOID LogPrereaderBase::LGPDBEnable( const DBID dbid )
// Otherwise, we need to allocate all the data structures.
if ( FLGPDBEnabled( dbid ) )
{
- const CArray::ERR errSetSize = m_rgArrayPagerefs[ dbid ].ErrSetSize( 0 );
- Assert( errSetSize == CArray::ERR::errSuccess );
+ m_rgArrayPagerefs[ dbid ].Clear();
Assert( FLGPDBEnabled( dbid ) );
}
else
diff --git a/dev/ese/src/ese/_log/logread_legacy.cxx b/dev/ese/src/ese/_log/logread_legacy.cxx
index e8f1b931..7989bec7 100644
--- a/dev/ese/src/ese/_log/logread_legacy.cxx
+++ b/dev/ese/src/ese/_log/logread_legacy.cxx
@@ -528,7 +528,7 @@ INLINE BOOL FLGILogPatchDate( const WCHAR* wszPath, CPRINTFFILE **const ppcprint
// allocate a new trace file object
- pcprintf = new CPRINTFFILE( wszPath );
+ pcprintf = new CPRINTFFILE( wszPath, CPRINTFFILE::FILEENCODING::ASCII );
if ( !pcprintf )
{
return fFalse;
@@ -840,7 +840,7 @@ ERR LOG_READ_BUFFER::ErrLGCheckReadLastLogRecordFF_Legacy(
ULONG ulChecksumExpected;
ULONG ulChecksumActual;
#ifdef ENABLE_LOGPATCH_TRACE
- CPRINTFFILE *pcprintfLogPatch = NULL;
+ CPRINTFFILE * pcprintfLogPatch = NULL;
WCHAR wszLogPatchPath[ IFileSystemAPI::cchPathMax ];
#endif // ENABLE_LOGPATCH_TRACE
//
diff --git a/dev/ese/src/ese/_log/logredo.cxx b/dev/ese/src/ese/_log/logredo.cxx
index 6b9aaf7a..0f5b0def 100644
--- a/dev/ese/src/ese/_log/logredo.cxx
+++ b/dev/ese/src/ese/_log/logredo.cxx
@@ -179,10 +179,12 @@ LOCAL ERR ErrReplacePageImage(
Call( csr.ErrLoadPage( ppib, ifmp, pgno, pbBeforeImage, cb, latchWrite ) );
- // the before image of the page is logged after the dbtime was updated so we have to restore it
+ // the before image of the page is logged after the dbtime was updated so we have to revert it
+ csr.RevertDbtime( dbtimeBefore, csr.Cpage().FFlags() );
+
// Its also possible we are replaying a log on an available lag on a table which was deleted and reverted with fPageFDPDelete.
// We do not want to overwrite that flag.
- csr.RestoreDbtime( dbtimeBefore, fPageFDPDeleteBefore );
+ csr.Cpage().SetPageFDPDelete( fPageFDPDeleteBefore );
csr.Downgrade( latchRIW );
Assert( csr.Cpage().FPageFDPDelete() == fPageFDPDeleteBefore );
@@ -2277,13 +2279,23 @@ LOCAL ERR ErrLGRIClearRedoMapDbtimeRevert( PIB* ppib, const LR* const plr, const
{
const LRMERGE_* const plrmerge = (LRMERGE_*)plr;
- // Merge is always done inside a Macro
- Assert( fMacroGoing );
-
// Add it to the list of pages freed, if empty.
if ( plrmerge->FEmptyPage() )
{
- CallR( ppib->ErrInsertPgnoFreed( dbtime, ifmp, plrmerge->le_pgno ) );
+ // Merge is always done inside a Macro
+ // If there is no macro for given dbtime, then macro begin must have been outside the checkpoint.
+ // We should be fine skipping reconciling such a page from dbtimerevert redomap as the macro would have had exclusive latch during merge
+ // and no other update on the page should be possible concurrently and shouldn't have been added to redomap.
+ //
+ if ( !fMacroGoing )
+ {
+ Assert( !pLogRedoMapToClear || !pLogRedoMapToClear->FPgnoSet( plrmerge->le_pgno ) );
+ return JET_errSuccess;
+ }
+ else
+ {
+ CallR( ppib->ErrInsertPgnoFreed( dbtime, ifmp, plrmerge->le_pgno ) );
+ }
}
break;
}
@@ -2378,7 +2390,7 @@ ERR LOG::ErrLGRIEndEverySession()
ERR LOG::ErrLGRIEndAllSessions(
const BOOL fEndOfLog,
- const BOOL fKeepDbAttached,
+ BOOL fKeepDbAttached,
const LE_LGPOS * ple_lgposRedoFrom,
BYTE * pbAttach )
{
@@ -2387,9 +2399,17 @@ ERR LOG::ErrLGRIEndAllSessions(
BOOL fNeedCallINSTTerm = fTrue;
DBID dbid;
- // UNDONE: is this call needed?
- //
- //(VOID)ErrVERRCEClean( );
+ // If we are close to the CheckpointTooDeep limit, do a clean RecoveryQuit even if asked for
+ // dirty cache keepalive recovery quit at the end of recovery.
+ if ( fKeepDbAttached && fEndOfLog )
+ {
+ const LONG lgenTooDeepLimit = (LONG)UlParam( m_pinst, JET_paramCheckpointTooDeep ) - lgenCheckpointTooDeepMin / 2;
+ const LONG lgenOutstanding = m_pLogStream->GetCurrentFileGen() - LgposGetCheckpoint().le_lGeneration;
+ if ( lgenOutstanding >= ( lgenTooDeepLimit * 90 ) / 100 )
+ {
+ fKeepDbAttached = fFalse;
+ }
+ }
// Set current time to attached db's dbfilehdr
@@ -3155,7 +3175,7 @@ ERR LOG::ErrLGRIRedoNodeOperation( const LRNODE_ *plrnode, ERR *perr )
err = ErrNDValidateSetExternalHeader( csr.Cpage(), &data );
if ( err < JET_errSuccess )
{
- OSUHAEmitFailureTag( m_pinst, HaDbFailureTagCorruption, L"630fa9f1-afcd-4998-bb82-db992a6eb22f" );
+ OSUHAEmitFailureTag( m_pinst, HaDbFailureTagLogLogicallyInconsistent, L"630fa9f1-afcd-4998-bb82-db992a6eb22f" );
Call( err );
}
@@ -3193,6 +3213,7 @@ ERR LOG::ErrLGRIRedoNodeOperation( const LRNODE_ *plrnode, ERR *perr )
}
// remove this RCE from the list of uncreated RCEs
+ Assert( !ppib->FDeferredRceid( plrundoinfo->le_rceid ) || g_rgfmp[ifmp].FContainsDataFromFutureLogs() );
Call( ppib->ErrDeregisterDeferredRceid( plrundoinfo->le_rceid ) );
Assert( trxOld == plrundoinfo->le_trxBegin0 );
@@ -3481,6 +3502,7 @@ ERR LOG::ErrLGRIRedoNodeOperation( const LRNODE_ *plrnode, ERR *perr )
// add this RCE to the list of uncreated RCEs
if ( plrfiard->FVersioned() )
{
+ Assert( g_rgfmp[ifmp].FContainsDataFromFutureLogs() );
Call( ppib->ErrRegisterDeferredRceid( plrfiard->le_rceidReplace, pgno ) );
}
@@ -3501,6 +3523,7 @@ ERR LOG::ErrLGRIRedoNodeOperation( const LRNODE_ *plrnode, ERR *perr )
// add this RCE to the list of uncreated RCEs
if ( plrreplace->FVersioned() )
{
+ Assert( g_rgfmp[ifmp].FContainsDataFromFutureLogs() );
Call( ppib->ErrRegisterDeferredRceid( plrnode->le_rceid, pgno ) );
}
@@ -3545,7 +3568,7 @@ ERR LOG::ErrLGRIRedoNodeOperation( const LRNODE_ *plrnode, ERR *perr )
// Assert( cb < sizeof( rgbRecNew ) );
if ( cb >= (SIZE_T)g_cbPage )
{
- OSUHAEmitFailureTag( m_pinst, HaDbFailureTagCorruption, L"dba4c055-bbbf-4fd1-a56d-e786519803eb" );
+ OSUHAEmitFailureTag( m_pinst, HaDbFailureTagLogLogicallyInconsistent, L"dba4c055-bbbf-4fd1-a56d-e786519803eb" );
Error( ErrERRCheck( JET_errLogCorrupted ) );
}
@@ -3560,7 +3583,11 @@ ERR LOG::ErrLGRIRedoNodeOperation( const LRNODE_ *plrnode, ERR *perr )
Assert( (ULONG)data.Cb() == cbNewData );
if ( (ULONG)data.Cb() != cbNewData )
{
- OSUHAEmitFailureTag( m_pinst, HaDbFailureTagCorruption, L"a3cb57b9-8ba1-496d-a6fc-4fc2f0140fc4" );
+ // per analysis of a real world case, it is hard to imagine how local (passive) data or remote (active)
+ // database data generated this incorrectness. This is literally saying the ib/cb pairs do NOT add up
+ // to the final record size (from the active). This almost assuredly means that there was a corruption
+ // of the actual log record data. Or a bug in our diff creation or reconstruction alg.
+ OSUHAEmitFailureTag( m_pinst, HaDbFailureTagLogLogicallyInconsistent, L"a3cb57b9-8ba1-496d-a6fc-4fc2f0140fc4" );
Error( ErrERRCheck( JET_errLogCorrupted ) );
}
@@ -3622,6 +3649,7 @@ ERR LOG::ErrLGRIRedoNodeOperation( const LRNODE_ *plrnode, ERR *perr )
// add this RCE to the list of uncreated RCEs
if ( plrflagdelete->FVersioned() )
{
+ Assert( g_rgfmp[ifmp].FContainsDataFromFutureLogs() );
Call( ppib->ErrRegisterDeferredRceid( plrnode->le_rceid, pgno ) );
}
@@ -4710,7 +4738,6 @@ ERR LOG::ErrLGRISetupFMPFromAttach(
IFMP ifmp = ifmpNil;
RSTMAP* psrtmap = NULL;
ULONG pctCachePriority = g_pctCachePriorityUnassigned;
- JET_GRBIT grbitShrinkDatabaseOptions = NO_GRBIT;
pifmp = pifmp ? pifmp : &ifmp;
pirstmap = pirstmap ? pirstmap : &irstmap;
@@ -4761,13 +4788,12 @@ ERR LOG::ErrLGRISetupFMPFromAttach(
// and set below in the FMP. Once recovery is finished, the DB needs to go through
// JetAttachDatabase anyways, so all DB parameters will be parsed and consumed then.
//
-
Call( ErrDBParseDbParams(
psrtmap ? psrtmap->rgsetdbparam : NULL,
psrtmap ? psrtmap->csetdbparam : 0,
NULL, // JET_dbparamDbSizeMaxPages (not used here).
&pctCachePriority, // JET_dbparamCachePriority.
- &grbitShrinkDatabaseOptions, // JET_dbparamShrinkDatabaseOptions.
+ NULL, // JET_dbparamShrinkDatabaseOptions (not used here).
NULL, // JET_dbparamShrinkDatabaseTimeQuota (not used here).
NULL, // JET_dbparamShrinkDatabaseSizeLimit (not used here).
NULL, // JET_dbparamLeakReclaimerEnabled (not used here).
@@ -4815,7 +4841,6 @@ ERR LOG::ErrLGRISetupFMPFromAttach(
pfmpT->ResetDeferredAttach();
pfmpT->SetPctCachePriorityFmp( pctCachePriority );
- pfmpT->SetShrinkDatabaseOptions( grbitShrinkDatabaseOptions );
FMP::EnterFMPPoolAsWriter();
pfmpT->SetLogOn();
@@ -4988,6 +5013,7 @@ ERR LOG::ErrLGRICheckRedoCreateDb(
m_pinst,
m_pinst->m_pfsapi,
wszDbName,
+ JET_filetypeDatabase,
(BYTE*)pdbfilehdr,
g_cbPage,
OffsetOf( DBFILEHDR, le_cbPageSize ) );
@@ -5236,6 +5262,7 @@ ERR LOG::ErrLGRICheckRedoAttachDb(
m_pinst,
m_pinst->m_pfsapi,
wszDbName,
+ JET_filetypeDatabase,
(BYTE*)pdbfilehdr,
g_cbPage,
OffsetOf( DBFILEHDR, le_cbPageSize ) );
@@ -5274,7 +5301,7 @@ ERR LOG::ErrLGRICheckRedoAttachDb(
goto HandleError;
}
}
- else if ( JET_errReadVerifyFailure == err )
+ else if ( FErrIsDbCorruption( err ) )
{
reason = eDARHeaderCorrupt;
if ( pfmp->FIgnoreDeferredAttach() )
@@ -5284,8 +5311,8 @@ ERR LOG::ErrLGRICheckRedoAttachDb(
}
else
{
- // the log file header is corrupt
- OSUHAEmitFailureTag( m_pinst, HaDbFailureTagRecoveryRedoLogCorruption, L"9106f5c1-2f93-479b-a12a-c93c6ab3de68" );
+ // the DB file header is corrupt
+ OSUHAEmitFailureTag( m_pinst, HaDbFailureTagCorruption, L"9106f5c1-2f93-479b-a12a-c93c6ab3de68" );
goto HandleError;
}
}
@@ -5350,7 +5377,7 @@ ERR LOG::ErrLGRICheckRedoAttachDb(
const BOOL fMatchingLoggedSignLog = ( 0 == memcmp( &pdbfilehdr->signLog, psignLogged, sizeof(SIGNATURE) ) );
// When we are recovering a dirty-and-patched database, it's possible that lGenMinRequired gets
- // stalled due to pending redo map entries. When that happens and there are mulitple attach/detach
+ // stalled due to pending redo map entries. When that happens and there are multiple attach/detach
// cycles before the redo map entries are resolved, we could have lgposAttach ahead of lGenMinRequired.
// In that case, we need to reset lGenMinRequired and lgposAttach so that we are forced to re-attach
// and rebuild the redo maps. Note that ErrIsamEndDatabaseIncrementalReseed() does something similar to
@@ -7335,7 +7362,7 @@ ERR LOG::ErrLGRIRedoOperation( LR *plr )
// This is because we will apply this root page move record only if we have preimage of the root.
if ( g_rgfmp[ ifmp ].FRBSOn() )
{
- CallR( g_rgfmp[ ifmp ].PRBS()->ErrCaptureRootPageMove( dbid, 0, plrcreatemefdp->le_pgno ) );
+ CallR( g_rgfmp[ ifmp ].PRBS()->ErrCaptureRootPageMove( dbid, 0, plrcreatemefdp->le_pgno, plrcreatemefdp->le_dbtime ) );
}
break;
@@ -7385,7 +7412,7 @@ ERR LOG::ErrLGRIRedoOperation( LR *plr )
// This is because we will apply this root page move record only if we have preimage of the root.
if ( g_rgfmp[ ifmp ].FRBSOn() )
{
- CallR( g_rgfmp[ ifmp ].PRBS()->ErrCaptureRootPageMove( dbid, 0, pgnoFDP ) );
+ CallR( g_rgfmp[ ifmp ].PRBS()->ErrCaptureRootPageMove( dbid, 0, pgnoFDP, plrcreatesefdp->le_dbtime ) );
}
break;
@@ -7724,8 +7751,8 @@ LOCAL ERR ErrLGIRedoSplitLineinfo( FUCB *pfucb,
if ( psplit->clines < 0 || psplit->clines > 1000000 )
{
- OSUHAEmitFailureTag( PinstFromPfucb( pfucb ), HaDbFailureTagRecoveryRedoLogCorruption, L"2dfb97c9-80ee-4438-ba68-0d4953cf09ad" );
- return ErrERRCheck( JET_errLogFileCorrupt );
+ OSUHAEmitFailureTag( PinstFromPfucb( pfucb ), HaDbFailureTagLogLogicallyInconsistent, L"2dfb97c9-80ee-4438-ba68-0d4953cf09ad" );
+ return ErrERRCheck( JET_errLogCorrupted );
}
AllocR( psplit->rglineinfo = new LINEINFO[psplit->clines] );
@@ -9620,7 +9647,7 @@ ERR LOG::ErrLGRIRedoScanCheck( const LRSCANCHECK2 * const plrscancheck, BOOL* co
Assert( cpage.CbPage() == UlParam( PinstFromIfmp( ifmp ), JET_paramDatabasePageSize ) );
const DBTIME dbtimePage = cpage.Dbtime();
const BOOL fInitDbtimePage = dbtimePage != 0 && dbtimePage != dbtimeShrunk;
- const BOOL fPageFDPDelete = cpage.FPageFDPDelete();
+ const BOOL fPageFDPDelete = !!( cpage.FPageFDPDelete() );
Expected( fInitDbtimePage || ( dbtimePage == dbtimeShrunk ) ); // dbtime 0 only usually comes from a completely uninit page (-1019).
const DBTIME dbtimeCurrentInLogRec = plrscancheck->DbtimeCurrent();
@@ -10089,8 +10116,7 @@ ERR LOG::ErrLGRIRedoScanCheck( const LRSCANCHECK2 * const plrscancheck, BOOL* co
(void)m_arrayPagerefSupercold.ErrSetCapacity( LNextPowerOf2( m_arrayPagerefSupercold.Size() + 1 ) );
}
- (void)m_arrayPagerefSupercold.ErrSetEntry( m_arrayPagerefSupercold.Size(),
- PageRef( plrscancheck->Dbid(), plrscancheck->Pgno() ) );
+ (void)m_arrayPagerefSupercold.ErrAppendEntry( PageRef( plrscancheck->Dbid(), plrscancheck->Pgno() ) );
}
// Ideally, we should check for the error returned when latching the page to filter out cases where
@@ -10965,7 +10991,7 @@ ERR LOG::ErrLGRIRedoRootPageMove( PIB* const ppib, const DBTIME dbtime )
// This is because we will apply this root page move record only if we have preimages of both the source and destination.
if ( g_rgfmp[ ifmp ].FRBSOn() )
{
- Call( g_rgfmp[ ifmp ].PRBS()->ErrCaptureRootPageMove( g_rgfmp[ ifmp ].Dbid(), rm.pgnoFDP, rm.pgnoNewFDP ) );
+ Call( g_rgfmp[ ifmp ].PRBS()->ErrCaptureRootPageMove( g_rgfmp[ ifmp ].Dbid(), rm.pgnoFDP, rm.pgnoNewFDP, rm.dbtimeAfter ) );
}
HandleError:
@@ -10984,7 +11010,8 @@ ERR LOG::ErrLGRIRedoMacroOperation( PIB *ppib, DBTIME dbtime )
if ( plr == NULL )
{
FireWall( "NullLrOnRedoMacro" );
- return ErrERRCheck( JET_errLogFileCorrupt );
+ OSUHAEmitFailureTag( PinstFromPpib( ppib ), HaDbFailureTagLogLogicallyInconsistent, L"5ccd5865-becc-4c71-9eed-14756d0b0397" );
+ return ErrERRCheck( JET_errLogCorrupted );
}
LRTYP lrtyp = plr->lrtyp;
@@ -11053,12 +11080,6 @@ ERR LOG::ErrLGRIRedoExtendDB( const LREXTENDDB * const plrdbextension )
const BOOL fLgposLastResizeSet = ( CmpLgpos( lgposLastResize, lgposMin ) != 0 );
const INT icmpLgposLastVsCurrent = CmpLgpos( lgposLastResize, m_lgposRedo );
-#ifndef DEBUG
- const BOOL fMaySkipOlderResize = fLgposLastResizeSet && pfmp->FShrinkDatabaseEofOnAttach();
-#else
- const BOOL fMaySkipOlderResize = fLgposLastResizeSet;
-#endif
-
Assert( !fLgposLastResizeSet || fLgposLastResizeSupported );
{
OnDebug( PdbfilehdrReadOnly pdbfilehdr = pfmp->Pdbfilehdr() );
@@ -11070,9 +11091,7 @@ ERR LOG::ErrLGRIRedoExtendDB( const LREXTENDDB * const plrdbextension )
// that may have been initiated after the physical resizing of the file and the stamping of lgposLastResize to
// the header, but before the logical file size is updated post-OE operation. In that case, not replaying a
// matching lgposLastResize would leave the file with the smaller (logical) size captured by backup-start.
- if ( fMaySkipOlderResize &&
- fLgposLastResizeSet &&
- ( icmpLgposLastVsCurrent > 0 ) )
+ if ( fLgposLastResizeSet && ( icmpLgposLastVsCurrent > 0 ) )
{
OSTraceFMP( ifmp, JET_tracetagSpaceManagement,
OSFormat( "%hs: Skipping ExtendDB because we're replaying the initial required range and we haven't reached the last resize yet.", __FUNCTION__ ) );
@@ -11543,6 +11562,10 @@ ERR LOG::ErrLGRIRedoExtentFreed( const LREXTENTFREED2 * const plrextentfreed )
if ( fTableRootPage )
{
+ // If this database was reverted and we redo'ing an extent freed LR on root page, we should be seeing fPageFDPDelete flag set on the page when it was reverted.
+ LGPOS lgposCommitBeforeRevert = pfmp->Pdbfilehdr()->le_lgposCommitBeforeRevert;
+ BOOL fPageFDPDeleteFlagExpected = BoolParam( m_pinst, JET_paramFlight_EnableFDPDeleteFlagCheckOnExtentFreedRedo ) && !pfmp->FContainsDataFromFutureLogs() && ( CmpLgpos( lgposCommitBeforeRevert, m_lgposRedo ) > 0 );
+
// Capture the preimage of the table root and pass flag to indicate this is a delete table so that we special mark this table when reverted.
// We should generally not be touching the table pages before table delete.
// But in case we did due to some bug or some unexpected scenario, we will pass fRBSPreimageRevertAlways to make sure we always keep the table deleted.
@@ -11551,6 +11574,7 @@ ERR LOG::ErrLGRIRedoExtentFreed( const LREXTENTFREED2 * const plrextentfreed )
pgnoFirst,
dbtimeLast,
fRBSDeletedTableRootPage,
+ fPageFDPDeleteFlagExpected,
BfpriBFMake( PctFMPCachePriority( ifmp ), (BFTEMPOSFILEQOS) qosIODispatchImmediate ),
TcCurr() );
@@ -11561,6 +11585,37 @@ ERR LOG::ErrLGRIRedoExtentFreed( const LREXTENTFREED2 * const plrextentfreed )
BFMarkAsSuperCold( ifmp, pgnoFirst );
err = JET_errSuccess;
}
+
+ if ( err == JET_errRBSRedeleteFDPExpected )
+ {
+ OSTraceSuspendGC();
+ const WCHAR* rgwsz[] =
+ {
+ pfmp->WszDatabaseName(),
+ OSFormatW( L"%I32u (0x%08x)", pgnoFirst, pgnoFirst ),
+ OSFormatW( L"(%08I32X,%04hX,%04hX)", m_lgposRedo.lGeneration, m_lgposRedo.isec, m_lgposRedo.ib ),
+ OSFormatW( L"(%08I32X,%04hX,%04hX)", lgposCommitBeforeRevert.lGeneration, lgposCommitBeforeRevert.isec, lgposCommitBeforeRevert.ib ),
+ };
+
+ // Raise corruption event
+ UtilReportEvent(
+ eventError,
+ DATABASE_CORRUPTION_CATEGORY,
+ DB_PAGE_FDP_REDELETE_EXPECTED_ID,
+ _countof( rgwsz ),
+ rgwsz,
+ 0,
+ NULL,
+ pfmp->Pinst() );
+
+ OSUHAPublishEvent(
+ HaDbFailureTagCorruption, pfmp->Pinst(), HA_DATABASE_CORRUPTION_CATEGORY,
+ HaDbIoErrorNone, pfmp->WszDatabaseName(), 0, 0,
+ HA_DB_PAGE_FDP_REDELETE_EXPECTED_ID, _countof( rgwsz ), rgwsz );
+
+ OSTraceResumeGC();
+ }
+
CallR( err );
}
else if ( fEmptyPageFDPDeleted )
@@ -12064,8 +12119,7 @@ ERR LOG::ErrLGRIRedoOperations(
}
}
- const CArray::ERR errArray = m_arrayPagerefSupercold.ErrSetSize( 0 );
- Assert( errArray == CArray::ERR::errSuccess );
+ m_arrayPagerefSupercold.Clear();
// we report the progress either if this log took too long to replay (at least 5 seconds) or
// if the control callback says so ...
diff --git a/dev/ese/src/ese/_log/logstream.cxx b/dev/ese/src/ese/_log/logstream.cxx
index e187f46d..1989d5c9 100644
--- a/dev/ese/src/ese/_log/logstream.cxx
+++ b/dev/ese/src/ese/_log/logstream.cxx
@@ -50,7 +50,7 @@ LOG_STREAM::LOG_STREAM( INST * pinst, LOG * pLog )
m_fCreateAsynchZeroFilled( fFalse ),
m_errCreateAsynch( JET_errSuccess ),
// Asynchronous log file creation
- m_asigCreateAsynchIOCompleted( CSyncBasicInfo( _T( "LOG::m_asigCreateAsynchIOCompleted" ) ) ),
+ m_asigCreateAsynchIOCompleted( CSyncBasicInfo( "LOG::m_asigCreateAsynchIOCompleted" ) ),
m_critCreateAsynchIOExecuting( CLockBasicInfo( CSyncBasicInfo( "LOG::m_critCreateAsynchIOExecuting" ), rankAsynchIOExecuting, 0 ) ),
m_lgposCreateAsynchTrigger( lgposMax ),
m_critJetTmpLog( CLockBasicInfo( CSyncBasicInfo( szJetTmpLog ), rankJetTmpLog, 0 ) ),
diff --git a/dev/ese/src/ese/_log/logutil.cxx b/dev/ese/src/ese/_log/logutil.cxx
index 66a0d77f..839343e8 100644
--- a/dev/ese/src/ese/_log/logutil.cxx
+++ b/dev/ese/src/ese/_log/logutil.cxx
@@ -33,6 +33,7 @@ ERR ErrLGCheckDBFiles(
pinst,
pinst->m_pfsapi,
wszDatabase,
+ JET_filetypeDatabase,
(BYTE*)pdbfilehdrDb,
g_cbPage,
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ),
diff --git a/dev/ese/src/ese/_log/logwrite.cxx b/dev/ese/src/ese/_log/logwrite.cxx
index c68f7c11..41c277e7 100644
--- a/dev/ese/src/ese/_log/logwrite.cxx
+++ b/dev/ese/src/ese/_log/logwrite.cxx
@@ -162,9 +162,9 @@ LOG_WRITE_BUFFER::LOG_WRITE_BUFFER( INST * pinst, LOG * pLog, ILogStream * pLogS
// we always start writing to a new sector, so we never have a shadow sector to start with
m_fHaveShadow( fFalse ),
m_sigLogPaused( CSyncBasicInfo( "LOG_WRITE_BUFFER::sigLogPaused" ) ),
- m_semLogSignal( CSyncBasicInfo( _T( "LOG::m_semLogSignal" ) ) ),
- m_semLogWrite( CSyncBasicInfo( _T( "LOG::m_semLogWrite" ) ) ),
- m_semWaitForLogBufferSpace( CSyncBasicInfo( _T( "LOG::m_semWaitForLogBufferSpace" ) ) ),
+ m_semLogSignal( CSyncBasicInfo( "LOG::m_semLogSignal" ) ),
+ m_semLogWrite( CSyncBasicInfo( "LOG::m_semLogWrite" ) ),
+ m_semWaitForLogBufferSpace( CSyncBasicInfo( "LOG::m_semWaitForLogBufferSpace" ) ),
m_critLGWaitQ( CLockBasicInfo( CSyncBasicInfo( szLGWaitQ ), rankLGWaitQ, 0 ) ),
m_tickNextLazyCommit( 0 ),
m_lgposNextLazyCommit( lgposMin ),
diff --git a/dev/ese/src/ese/_log/rstmap.cxx b/dev/ese/src/ese/_log/rstmap.cxx
index ffa88c16..d6467552 100644
--- a/dev/ese/src/ese/_log/rstmap.cxx
+++ b/dev/ese/src/ese/_log/rstmap.cxx
@@ -547,6 +547,7 @@ ERR ErrRstmapSoftCheckDBFiles( INST *pinst, RSTMAP * pDbMapEntry )
pinst,
pinst->m_pfsapi,
wszDatabase,
+ JET_filetypeDatabase,
(BYTE*)pdbfilehdrDb,
g_cbPage,
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ),
diff --git a/dev/ese/src/ese/_osu/checksumu.cxx b/dev/ese/src/ese/_osu/checksumu.cxx
index c124d757..a0a717bc 100644
--- a/dev/ese/src/ese/_osu/checksumu.cxx
+++ b/dev/ese/src/ese/_osu/checksumu.cxx
@@ -50,8 +50,6 @@ deal with that.
#include "osustd.hxx"
#include "esestd.hxx"
-
-
// ================================================================
XECHECKSUM LongChecksumFromShortChecksum( const ULONG xorChecksum, const ULONG pgno )
// ================================================================
@@ -108,8 +106,8 @@ UINT IbitNewChecksumFormatFlag( const PAGETYPE pagetype )
// for database pages, the page flags are stored in the 10th
// unsigned long. The format bit is 0x2000, which is the 14th bit
//
- Assert( OffsetOf( CPAGE::PGHDR, fFlags ) * 8 == 9 * 32 );
- Assert( CPAGE::fPageNewChecksumFormat == ( 1 << 13 ) );
+ static_assert( OffsetOf( CPAGE::PGHDR, fFlags ) * 8 == 9 * 32 );
+ static_assert( CPAGE::fPageNewChecksumFormat == ( 1 << 13 ) );
return ( 9 * 32 ) + 13;
}
@@ -267,19 +265,18 @@ ULONG CbBlockSize( const ULONG cb )
}
// ================================================================
-static PAGECHECKSUM ComputePageChecksum(
+LOCAL PAGECHECKSUM ComputePageChecksum_(
const void* const pv,
const UINT cb,
const PAGETYPE pagetype,
const ULONG pgno,
- // set fNew to compute new ECC for a page (R/W wrt the large page!!)
- // reset fNew to computer ECC for verification purpose (R/O wrt the page)
- const BOOL fNew = fFalse )
+ const BOOL fNewChecksumFormat,
+ const BOOL fWriteChecksum )
// ================================================================
{
if( FPageHasLongChecksum( pagetype ) )
{
- if( FPageHasNewChecksumFormat( pv, pagetype ) )
+ if( fNewChecksumFormat )
{
// large pages (16/32kiB) always have new checksum format
PAGECHECKSUM pgChecksum;
@@ -311,7 +308,7 @@ static PAGECHECKSUM ComputePageChecksum(
// write checksums into designated location in header block
// so checksum for header block can protect them as well
- if ( fNew )
+ if ( fWriteChecksum )
{
// cast RO pv to RW pPgHdr2
CPAGE::PGHDR2* const pPgHdr2 = ( CPAGE::PGHDR2* )pv;
@@ -334,6 +331,18 @@ static PAGECHECKSUM ComputePageChecksum(
return ChecksumOldFormat((unsigned char *)pv, cb);
}
+// ================================================================
+static PAGECHECKSUM ComputePageChecksum(
+ const void* const pv,
+ const UINT cb,
+ const PAGETYPE pagetype,
+ const ULONG pgno,
+ const BOOL fWriteChecksum = fFalse )
+// ================================================================
+{
+ return ComputePageChecksum_( pv, cb, pagetype, pgno, FPageHasNewChecksumFormat( pv, pagetype ), fWriteChecksum );
+}
+
// ================================================================
enum XECHECKSUMERROR { xeChecksumNoError = 0, xeChecksumCorrectableError = -13, xeChecksumFatalError = -29, };
@@ -383,7 +392,7 @@ static void TryFixPage(
UINT ibT = 0;
XECHECKSUMERROR rgErr[ cxeChecksumPerPage ] = { xeChecksumNoError, };
- UINT rgibitCorrupted[ cxeChecksumPerPage ] = { IbitNewChecksumFormatFlag( pagetype ), UINT_MAX, UINT_MAX, UINT_MAX, };
+ UINT rgibitCorrupted[ cxeChecksumPerPage ] = { UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, };
UINT ibitCorrupted = UINT_MAX;
// work out correction
@@ -488,11 +497,25 @@ void ChecksumAndPossiblyFixPage(
*pchecksumExpected = ChecksumFromPage( pv, cb, pagetype );
*pchecksumActual = ComputePageChecksum( pv, cb, pagetype, pgno );
-
+
const BOOL fNewChecksumFormat = FPageHasNewChecksumFormat( pv, pagetype );
- if( *pchecksumActual != *pchecksumExpected && fNewChecksumFormat )
+ if ( *pchecksumActual != *pchecksumExpected && *pchecksumExpected != PAGECHECKSUM{ 0 } )
{
- TryFixPage( pv, cb, pagetype, fCorrectError, pfCorrectableError, pibitCorrupted, *pchecksumExpected, *pchecksumActual );
+ // Try correcting bit flips in the page for non-zero pages. (Pages whose checksum isn't 0).
+ // Note that a valid old format checksum can be 0 for some combination of non-zero bits on the page.
+ // A valid new checksum can't be zero because it comprises of two complimentary checksums,
+ // both of which can only be 0 if all of the bits on the page are 0 or 1.
+ // See checksum_amd64.cxx for a detailed description of why that is true.
+
+ // Old checksum format doesn't support error correction.
+ // But it could be that the checksum was new format and the bit that indicated formats got flipped.
+ // Compute the checksum as new format and try fixing it.
+ // If it is fixable, then we know that fNewChecksumFormat bit on the page got flipped.
+ PAGECHECKSUM checksumNewFormat = fNewChecksumFormat ?
+ *pchecksumActual :
+ ComputePageChecksum_( pv, cb, pagetype, pgno, fTrue, fFalse );
+
+ TryFixPage( pv, cb, pagetype, fCorrectError, pfCorrectableError, pibitCorrupted, *pchecksumExpected, checksumNewFormat );
Assert( ( *pfCorrectableError && *pibitCorrupted != -1 ) || ( !*pfCorrectableError && *pibitCorrupted == -1 ) );
// no point in re-computing the checksum if we haven't done any changes
@@ -524,13 +547,13 @@ void DumpLargePageChecksumInfo(
{
PAGECHECKSUM checksumStoredInHeader = ChecksumFromPage( pv, cb, pagetype );
PAGECHECKSUM checksumComputedOffData = ComputePageChecksum( pv, cb, pagetype, pgno );
- (*pcprintf)( _T( "HEADER checksum = 0x%016I64X:0x%016I64X:0x%016I64X:0x%016I64X\n" ),
+ (*pcprintf)( "HEADER checksum = 0x%016I64X:0x%016I64X:0x%016I64X:0x%016I64X\n",
checksumStoredInHeader.rgChecksum[ 0 ], checksumStoredInHeader.rgChecksum[ 1 ], checksumStoredInHeader.rgChecksum[ 2 ], checksumStoredInHeader.rgChecksum[ 3 ] );
if( checksumStoredInHeader != checksumComputedOffData )
{
- (*pcprintf)( _T( "****** checksum mismatch ******\n" ) );
- (*pcprintf)( _T( "COMPUTED checksum = 0x%016I64X:0x%016I64X:0x%016I64X:0x%016I64X\n" ),
+ (*pcprintf)( "****** checksum mismatch ******\n" );
+ (*pcprintf)( "COMPUTED checksum = 0x%016I64X:0x%016I64X:0x%016I64X:0x%016I64X\n",
checksumComputedOffData.rgChecksum[ 0 ], checksumComputedOffData.rgChecksum[ 1 ], checksumComputedOffData.rgChecksum[ 2 ], checksumComputedOffData.rgChecksum[ 3 ] );
BOOL fCorrectableError = fFalse;
@@ -539,15 +562,15 @@ void DumpLargePageChecksumInfo(
if ( !fCorrectableError )
{
- (*pcprintf)( _T( "error is NOT correctable by the checksum\n" ) );
+ (*pcprintf)( "error is NOT correctable by the checksum\n" );
}
else
{
Assert( 0 <= ibitCorrupted && ( unsigned )ibitCorrupted <= CHAR_BIT * cb );
- (*pcprintf)( _T( "a bit at offset %d (0x%X) was corrupted and can be corrected by the checksum\n" ), ibitCorrupted, ibitCorrupted );
+ (*pcprintf)( "a bit at offset %d (0x%X) was corrupted and can be corrected by the checksum\n", ibitCorrupted, ibitCorrupted );
const PAGECHECKSUM checksumFixed = ComputePageChecksum( pv, cb, pagetype, pgno );
- (*pcprintf)( _T( "FIXED checksum = 0x%016I64X:0x%016I64X:0x%016I64X:0x%016I64X\n" ),
+ (*pcprintf)( "FIXED checksum = 0x%016I64X:0x%016I64X:0x%016I64X:0x%016I64X\n",
checksumFixed.rgChecksum[ 0 ], checksumFixed.rgChecksum[ 1 ], checksumFixed.rgChecksum[ 2 ], checksumFixed.rgChecksum[ 3 ] );
Assert( checksumFixed == checksumStoredInHeader );
}
@@ -555,7 +578,7 @@ void DumpLargePageChecksumInfo(
}
EXCEPT( efaExecuteHandler )
{
- (*pcprintf)( _T( "\t\n" ) );
+ (*pcprintf)( "\t\n" );
}
ENDEXCEPT
}
@@ -582,56 +605,56 @@ void DumpPageChecksumInfo(
const BOOL fNewChecksumFormat = FPageHasNewChecksumFormat( pv, pagetype );
const BOOL fBadChecksum = ( checksumStoredInHeader != checksumComputedOffData );
- (*pcprintf)( _T( "\theader checksum = 0x%016I64x\n" ), checksumStoredInHeader.rgChecksum[ 0 ] );
+ (*pcprintf)( "\theader checksum = 0x%016I64x\n", checksumStoredInHeader.rgChecksum[ 0 ] );
if( fBadChecksum )
{
- (*pcprintf)( _T( "\t****** checksum mismatch ******\n" ) );
- (*pcprintf)( _T( "\tcomputed checksum = 0x%016I64x\n" ), checksumComputedOffData );
+ (*pcprintf)( "\t****** checksum mismatch ******\n" );
+ (*pcprintf)( "\tcomputed checksum = 0x%016I64x\n", checksumComputedOffData );
}
if( !fNewChecksumFormat )
{
- (*pcprintf)( _T( "\t\told checksum format\n" ) );
+ (*pcprintf)( "\t\told checksum format\n" );
const ULONG * pdw = (const ULONG * ) pv;
const ULONG pgnoFromPage = pdw[1];
- (*pcprintf)( _T( "\t\t\tpgno = %d\n" ), pgnoFromPage );
+ (*pcprintf)( "\t\t\tpgno = %d\n", pgnoFromPage );
}
else
{
- (*pcprintf)( _T( "\t\tnew checksum format\n" ) );
+ (*pcprintf)( "\t\tnew checksum format\n" );
const ULONG eccChecksumComputed = DwECCChecksumFromXEChecksum( checksumComputedOffData.rgChecksum[ 0 ] );
const ULONG xorChecksumComputed = DwXORChecksumFromXEChecksum( checksumComputedOffData.rgChecksum[ 0 ] );
const ULONG eccChecksumHeader = DwECCChecksumFromXEChecksum( checksumStoredInHeader.rgChecksum[ 0 ] );
const ULONG xorChecksumHeader = DwXORChecksumFromXEChecksum( checksumStoredInHeader.rgChecksum[ 0 ] );
- (*pcprintf)( _T( "\t\t\theader ECC checksum = 0x%08x\n" ), eccChecksumHeader );
+ (*pcprintf)( "\t\t\theader ECC checksum = 0x%08x\n", eccChecksumHeader );
if( fBadChecksum )
{
- (*pcprintf)( _T( "\t\t\tcomputed ECC checksum = 0x%08x\n" ), eccChecksumComputed );
+ (*pcprintf)( "\t\t\tcomputed ECC checksum = 0x%08x\n", eccChecksumComputed );
}
- (*pcprintf)( _T( "\t\t\theader XOR checksum = 0x%08x\n" ), xorChecksumHeader );
+ (*pcprintf)( "\t\t\theader XOR checksum = 0x%08x\n", xorChecksumHeader );
if( fBadChecksum )
{
- (*pcprintf)( _T( "\t\t\tcomputed XOR checksum = 0x%08x\n" ), xorChecksumComputed );
+ (*pcprintf)( "\t\t\tcomputed XOR checksum = 0x%08x\n", xorChecksumComputed );
}
if( fBadChecksum )
{
if( !FECCErrorIsCorrectable( cb, checksumStoredInHeader.rgChecksum[ 0 ], checksumComputedOffData.rgChecksum[ 0 ] ) )
{
- (*pcprintf)( _T( "\tchecksum error is NOT correctable\n" ) );
+ (*pcprintf)( "\tchecksum error is NOT correctable\n" );
if( eccChecksumComputed == eccChecksumHeader )
{
const ULONG pgnoPossible = xorChecksumComputed ^ xorChecksumHeader ^ pgno;
- (*pcprintf)( _T( "\tECC checksums match. perhaps this is actually page %d?\n" ), pgnoPossible );
+ (*pcprintf)( "\tECC checksums match. perhaps this is actually page %d?\n", pgnoPossible );
}
}
else
{
- (*pcprintf)( _T( "\tchecksum error is correctable\n" ) );
+ (*pcprintf)( "\tchecksum error is correctable\n" );
const UINT ibitCorrupted = IbitCorrupted( cb, checksumStoredInHeader.rgChecksum[ 0 ], checksumComputedOffData.rgChecksum[ 0 ] );
- (*pcprintf)( _T( "\t\tbit %d is corrupted\n" ), ibitCorrupted );
+ (*pcprintf)( "\t\tbit %d is corrupted\n", ibitCorrupted );
if( IbitNewChecksumFormatFlag( pagetype ) == ibitCorrupted )
{
- (*pcprintf)( _T( "\t\tbit %d is the checksum format flag! this corruption is not fixable\n" ), ibitCorrupted );
+ (*pcprintf)( "\t\tbit %d is the checksum format flag! this corruption is not fixable\n", ibitCorrupted );
}
else
{
@@ -639,16 +662,16 @@ void DumpPageChecksumInfo(
const PAGECHECKSUM checksumFixed = ComputePageChecksum( pv, cb, pagetype, pgno );
const ULONG eccChecksumFixed = DwECCChecksumFromXEChecksum( checksumFixed.rgChecksum[ 0 ] );
const ULONG xorChecksumFixed = DwXORChecksumFromXEChecksum( checksumFixed.rgChecksum[ 0 ] );
- (*pcprintf)( _T( "\t\tfixed checksum is 0x%016I64x\n" ), checksumFixed );
- (*pcprintf)( _T( "\t\tfixed ECC checksum is 0x%08x\n" ), eccChecksumFixed );
- (*pcprintf)( _T( "\t\tfixed XOR checksum is 0x%08x\n" ), xorChecksumFixed );
+ (*pcprintf)( "\t\tfixed checksum is 0x%016I64x\n", checksumFixed );
+ (*pcprintf)( "\t\tfixed ECC checksum is 0x%08x\n", eccChecksumFixed );
+ (*pcprintf)( "\t\tfixed XOR checksum is 0x%08x\n", xorChecksumFixed );
if( checksumFixed == checksumStoredInHeader )
{
- (*pcprintf)( _T( "\t****** page corruption was fixed ******\n" ) );
+ (*pcprintf)( "\t****** page corruption was fixed ******\n" );
}
else
{
- (*pcprintf)( _T( "\t****** page corruption fix FAILED! ******\n" ) );
+ (*pcprintf)( "\t****** page corruption fix FAILED! ******\n" );
}
}
}
@@ -657,7 +680,7 @@ void DumpPageChecksumInfo(
}
EXCEPT( efaExecuteHandler )
{
- (*pcprintf)( _T( "\t\n" ) );
+ (*pcprintf)( "\t\n" );
}
ENDEXCEPT
}
diff --git a/dev/ese/src/ese/_osu/encryptu.cxx b/dev/ese/src/ese/_osu/encryptu.cxx
index 137c37d9..66e9d385 100644
--- a/dev/ese/src/ese/_osu/encryptu.cxx
+++ b/dev/ese/src/ese/_osu/encryptu.cxx
@@ -75,7 +75,31 @@ ErrOSUEncrypt(
PERFOpt( cEncryptionCalls.Inc( iInstance, tce ) );
const HRT hrtStart = HrtHRTCount();
- const ERR err = ErrOSEncryptWithAes256( pbData, pcbDataLen, cbDataBufLen, pfucbTable->pbEncryptionKey, pfucbTable->cbEncryptionKey );
+#ifdef DEBUG
+ ULONG cbDataIn = *pcbDataLen;
+ BYTE *pbDataCopy = new BYTE[cbDataIn];
+ if ( pbDataCopy != NULL )
+ {
+ memcpy_s( pbDataCopy, cbDataIn, pbData, cbDataIn );
+ }
+#endif
+ const ERR err = ErrOSEncryptWithAes256( PARAM_AES256_IMPLEMENTATION, pbData, pcbDataLen, cbDataBufLen, pfucbTable->pbEncryptionKey, pfucbTable->cbEncryptionKey );
+#ifdef DEBUG
+ // On debug, verify that other encryption implementation can decrypt the result back to the original buffer.
+ if ( err >= JET_errSuccess && pbDataCopy != NULL )
+ {
+ ULONG cbDataOut = *pcbDataLen;
+ BYTE *pbDataOutCopy = new BYTE[cbDataOut];
+ if ( pbDataOutCopy != NULL )
+ {
+ CallS( ErrOSDecryptWithAes256( OTHER_AES256_IMPLEMENTATION, pbData, pbDataOutCopy, &cbDataOut, pfucbTable->pbEncryptionKey, pfucbTable->cbEncryptionKey ) );
+ Assert( cbDataIn == cbDataOut );
+ Assert( memcmp( pbDataCopy, pbDataOutCopy, cbDataIn ) == 0 );
+ delete[] pbDataOutCopy;
+ }
+ }
+ delete[] pbDataCopy;
+#endif
PERFOpt( cEncryptionTotalDhrts.Add( iInstance, tce, HrtHRTCount() - hrtStart ) );
return err;
@@ -100,7 +124,7 @@ ErrOSUDecrypt(
PERFOpt( cDecryptionCalls.Inc( iInstance, tce ) );
const HRT hrtStart = HrtHRTCount();
- const ERR err = ErrOSDecryptWithAes256( pbDataIn, pbDataOut, pcbDataLen, pfucbTable->pbEncryptionKey, pfucbTable->cbEncryptionKey );
+ const ERR err = ErrOSDecryptWithAes256( PARAM_AES256_IMPLEMENTATION, pbDataIn, pbDataOut, pcbDataLen, pfucbTable->pbEncryptionKey, pfucbTable->cbEncryptionKey );
PERFOpt( cDecryptionTotalDhrts.Add( iInstance, tce, HrtHRTCount() - hrtStart ) );
if ( err == JET_errDecryptionFailed )
diff --git a/dev/ese/src/ese/_osu/fileu.cxx b/dev/ese/src/ese/_osu/fileu.cxx
index 12c91c57..d90d4d06 100644
--- a/dev/ese/src/ese/_osu/fileu.cxx
+++ b/dev/ese/src/ese/_osu/fileu.cxx
@@ -196,79 +196,63 @@ ERR ErrUtilReadSpecificShadowedHeader( const INST* const pinst, DB_HEADER_READER
//
for ( cbPageCandidate = cbPageCandidateMin ; cbPageCandidate <= cbPageCandidateMax && cbAlloc > 0 ; cbPageCandidate *= 2 )
{
- if ( FRangeContains( ibRead, cbRead, 0 * cbPageCandidate, cbPageCandidate ) ||
- ( cbAlloc >= cbPageCandidate &&
- pfapiRead->ErrIORead( *tcHeader, QWORD( 0 * cbPageCandidate ), cbPageCandidate, pbRead + 0 * cbPageCandidate, qos ) >= JET_errSuccess ) )
+ for ( int i = 0; i < 2; i++ )
{
- ChecksumPage( pbRead + 0 * cbPageCandidate,
- cbPageCandidate,
- databaseHeader,
- 0,
- &checksumExpected,
- &checksumActual );
- if ( checksumActual == checksumExpected ||
- BoolParam( JET_paramDisableBlockVerification ) )
+ if ( FRangeContains( ibRead, cbRead, i * cbPageCandidate, cbPageCandidate ) ||
+ ( cbAlloc >= ( i + 1 ) * cbPageCandidate &&
+ pfapiRead->ErrIORead( *tcHeader, QWORD( i * cbPageCandidate ), cbPageCandidate, pbRead + i * cbPageCandidate, qos ) >= JET_errSuccess ) )
{
- if ( ibPageSize >= 0 )
+ ChecksumPage( pbRead + i * cbPageCandidate,
+ cbPageCandidate,
+ databaseHeader,
+ 0,
+ &checksumExpected,
+ &checksumActual );
+ if ( checksumActual == checksumExpected ||
+ BoolParam( JET_paramDisableBlockVerification ) )
{
- if ( cbPageCandidate >= ibPageSize + sizeof( UnalignedLittleEndian ) )
+ const ULONG filetype = *( ( UnalignedLittleEndian* )( pbRead + i * cbPageCandidate + offsetof( DBFILEHDR, le_filetype ) ) );
+ if ( pdbHdrReader->filetype == JET_filetypeUnknown )
{
- ULONG cbPageHeader = *( (UnalignedLittleEndian *)( pbRead + 0 * cbPageCandidate + ibPageSize ) );
- if ( FValidCbPage( cbPageHeader ) )
- {
- if ( cbPageHeader == 0 )
- {
- cbPageHeader = g_cbPageDefault;
- }
- if ( cbPageHeader == cbPageCandidate )
- {
- cbPagePrimary = cbPageCandidate;
- MergeRange( &ibRead, &cbRead, 0 * cbPageCandidate, cbPageCandidate );
- }
- }
}
- }
- else
- {
- cbPagePrimary = cbPageCandidate;
- }
- }
- }
- if ( FRangeContains( ibRead, cbRead, 1 * cbPageCandidate, cbPageCandidate ) ||
- ( cbAlloc >= 2 * cbPageCandidate &&
- pfapiRead->ErrIORead( *tcHeader, QWORD( 1 * cbPageCandidate ), cbPageCandidate, pbRead + 1 * cbPageCandidate, qos ) >= JET_errSuccess ) )
- {
- ChecksumPage( pbRead + 1 * cbPageCandidate,
- cbPageCandidate,
- databaseHeader,
- 0,
- &checksumExpected,
- &checksumActual );
- if ( checksumActual == checksumExpected ||
- BoolParam( JET_paramDisableBlockVerification ) )
- {
- if ( ibPageSize >= 0 )
- {
- if ( cbPageCandidate >= ibPageSize + sizeof( UnalignedLittleEndian ) )
+ else if ( filetype == pdbHdrReader->filetype )
{
- ULONG cbPageHeader = *( (UnalignedLittleEndian *)( pbRead + 1 * cbPageCandidate + ibPageSize ) );
- if ( FValidCbPage( cbPageHeader ) )
+ }
+ else if ( filetype == JET_filetypeTempDatabase && pdbHdrReader->filetype == JET_filetypeDatabase )
+ {
+ }
+ else if ( BoolParam( JET_paramDisableBlockVerification ) )
+ {
+ }
+ else
+ {
+ Error( ErrERRCheck( JET_errFileInvalidType ) );
+ }
+
+ ULONG& cbPageOutput = i == 0 ? cbPagePrimary : cbPageSecondary;
+ if ( ibPageSize >= 0 )
+ {
+ if ( cbPageCandidate >= ibPageSize + sizeof( UnalignedLittleEndian ) )
{
- if ( cbPageHeader == 0 )
- {
- cbPageHeader = g_cbPageDefault;
- }
- if ( cbPageHeader == cbPageCandidate )
+ ULONG cbPageHeader = *( (UnalignedLittleEndian *)( pbRead + i * cbPageCandidate + ibPageSize ) );
+ if ( FValidCbPage( cbPageHeader ) )
{
- cbPageSecondary = cbPageCandidate;
- MergeRange( &ibRead, &cbRead, 1 * cbPageCandidate, cbPageCandidate );
+ if ( cbPageHeader == 0 )
+ {
+ cbPageHeader = g_cbPageDefault;
+ }
+ if ( cbPageHeader == cbPageCandidate )
+ {
+ cbPageOutput = cbPageCandidate;
+ MergeRange( &ibRead, &cbRead, i * cbPageCandidate, cbPageCandidate );
+ }
}
}
}
- }
- else
- {
- cbPageSecondary = cbPageCandidate;
+ else
+ {
+ cbPageOutput = cbPageCandidate;
+ }
}
}
}
@@ -488,6 +472,7 @@ LOCAL ERR ErrUtilIReadShadowedHeader(
const INST* const pinst,
IFileSystemAPI* const pfsapi,
const WCHAR* const wszFileName,
+ _In_ const ULONG filetype,
__out_bcount( cbHeader ) BYTE* pbHeader,
const DWORD cbHeader,
const LONG ibPageSize,
@@ -509,6 +494,7 @@ LOCAL ERR ErrUtilIReadShadowedHeader(
{
headerRequestGoodOnly, // shadowedHeaderRequest
wszFileName, // wszFileName
+ filetype, // filetype
pbHeader, // pbHeader
cbHeader, // cbHeader
ibPageSize, // ibPageSize
@@ -584,6 +570,7 @@ ERR ErrUtilReadShadowedHeader(
const INST* const pinst,
IFileSystemAPI* const pfsapi,
const WCHAR* const wszFilePath,
+ _In_ const ULONG filetype,
__out_bcount( cbHeader ) BYTE* pbHeader,
const DWORD cbHeader,
const LONG ibPageSize,
@@ -601,7 +588,7 @@ ERR ErrUtilReadShadowedHeader(
IFileAPI::fmfCached :
IFileAPI::fmfNone ) ),
&pfapi ) );
- Call( ErrUtilReadShadowedHeader( pinst, pfsapi, pfapi, pbHeader, cbHeader, ibPageSize, urhf, pcbHeaderActual, pShadowedHeaderStatus ) );
+ Call( ErrUtilReadShadowedHeader( pinst, pfsapi, pfapi, filetype, pbHeader, cbHeader, ibPageSize, urhf, pcbHeaderActual, pShadowedHeaderStatus ) );
HandleError:
delete pfapi;
@@ -616,6 +603,7 @@ ERR ErrUtilReadShadowedHeader(
const INST* const pinst,
IFileSystemAPI* const pfsapi,
IFileAPI* const pfapi,
+ _In_ const ULONG filetype,
__out_bcount( cbHeader ) BYTE* pbHeader,
const DWORD cbHeader,
const LONG ibPageSize,
@@ -641,6 +629,7 @@ ERR ErrUtilReadShadowedHeader(
Call( ErrUtilIReadShadowedHeader( pinst,
pfsapi,
wszFilePath,
+ filetype,
pbHeader,
cbHeader,
ibPageSize,
diff --git a/dev/ese/src/ese/_osu/hapublishu.cxx b/dev/ese/src/ese/_osu/hapublishu.cxx
index e0d0cdad..a8237d66 100644
--- a/dev/ese/src/ese/_osu/hapublishu.cxx
+++ b/dev/ese/src/ese/_osu/hapublishu.cxx
@@ -4,6 +4,8 @@
#include "osustd.hxx"
#include "esestd.hxx"
+
+
// The current layer is high enough to understand INST internal.
// Extracing m_wszInstanceName and m_wszDisplayName was
// not possible down inside OS layer
@@ -20,8 +22,25 @@ void OSUHAPublishEvent_(
DWORD cParameter,
const WCHAR** rgwszParameter )
{
+ BOOL fEmit = fTrue;
+
// failure events need not be published if there is no instance
- if ( pinstNil != pinst && UlParam( pinst, JET_paramEnableHaPublish ) )
+ // update: why?
+ if ( pinst == NULL || pinstNil == pinst )
+ {
+#ifdef ENABLE_MISSED_FAILURE_ITEM_TRACKING
+ FireWall( "SkipFi2NoInst" );
+#endif
+ fEmit = fFalse;
+ }
+
+ if ( pinstNil != pinst && !UlParam( pinst, JET_paramEnableHaPublish ) )
+ {
+ // might be nice to Assert/FireWall not O365 Datacenter / Store.worker, but a bit of a layer violation
+ fEmit = fFalse;
+ }
+
+ if ( fEmit )
{
OSUHAPublishEventImpl( haTag,
pinst->m_wszInstanceName,
@@ -130,11 +149,44 @@ void OSUHAEmitFailureTag_(
}
}
}
+ #define pinst pinstDoNotUseForRestOfFuncUse_pinstActual
+
+ // FUTURE: HA Publish is only for O365 datacenter, but even so this is a bit of a layering violation. We will
+ // add these temporarily to do a basic health check on O365 to see if we're dropping HA FailureItems from any ESE
+ // code paths.
+ const BOOL fO365StoreWorker = ( _wcsicmp( WszUtilProcessName(), L"Microsoft.Exchange.Store.Worker" ) == 0 );
+ const BOOL fO365DatacenterProcess =
+ fO365StoreWorker ||
+ ( _wcsicmp( WszUtilProcessName(), L"MSExchangeRepl" ) == 0 ) ||
+ ( _wcsicmp( WszUtilProcessName(), L"EdgeTransport" ) == 0 ) ||
+ ( _wcsicmp( WszUtilProcessName(), L"Microsoft.Exchange.DxStore.HA.Instance" ) == 0 ) ||
+ ( _wcsicmp( WszUtilProcessName(), L"Microsoft.Exchange.SharedCache" ) == 0 ) ||
+ ( _wcsicmp( WszUtilProcessName(), L"Microsoft.Exchange.Store.Service" ) == 0 ); // calls JET APIs, but should not actually start ese inst
+ // should we add eseutil?
// if the instance pointer is NULL then do not emit an event
//
if ( !pinstActual )
{
+#ifdef ENABLE_MISSED_FAILURE_ITEM_TRACKING
+ if ( !FInEmbeddedUnitTest() )
+ {
+ if ( haTag != HaDbFailureTagMemory )
+ {
+ CHAR szTag[60];
+ OSStrFormatA( szTag, sizeof( szTag ), "SkipFiNoInstProvided-%d", haTag );
+ FireWall( szTag );
+ }
+ else if ( !FOSLayerUp() )
+ {
+ FireWall( "SkipFiNoInstAllocBeforeOsInit" :
+ }
+ else
+ {
+ FireWall( "SkipFiNoInstAllocVictimNotFoundOrAcquired" );
+ }
+ }
+#endif
fEmit = fFalse;
}
@@ -142,6 +194,12 @@ void OSUHAEmitFailureTag_(
//
if ( pinstActual && !UlParam( pinstActual, JET_paramEnableHaPublish ) )
{
+#ifdef ENABLE_MISSED_FAILURE_ITEM_TRACKING
+ if ( fO365StoreWorker )
+ {
+ FireWall( "SkipFiHaPublishOff" );
+ }
+#endif
fEmit = fFalse;
}
@@ -151,6 +209,13 @@ void OSUHAEmitFailureTag_(
( !pinstActual->m_wszInstanceName || !pinstActual->m_wszInstanceName[ 0 ] ||
!pinstActual->m_wszDisplayName || !pinstActual->m_wszDisplayName[ 0 ] ) )
{
+ // many test processes have this off, but all real ESE instances should be correctly identified.
+#ifdef ENABLE_MISSED_FAILURE_ITEM_TRACKING
+ if ( fO365DatacenterProcess )
+ {
+ FireWall( "SkipFiNoInstOrDispName" );
+ }
+#endif
fEmit = fFalse;
}
@@ -158,6 +223,9 @@ void OSUHAEmitFailureTag_(
//
if ( haTag == HaDbFailureTagNoOp )
{
+#ifdef ENABLE_MISSED_FAILURE_ITEM_TRACKING
+ FireWall( "SkipFiTagNoOp" );
+#endif
fEmit = fFalse;
}
@@ -165,6 +233,9 @@ void OSUHAEmitFailureTag_(
//
if ( !wszGuid || !wszGuid[ 0 ] )
{
+#ifdef ENABLE_MISSED_FAILURE_ITEM_TRACKING
+ FireWall( "SkipFiNoGuid" );
+#endif
fEmit = fFalse;
}
@@ -176,6 +247,9 @@ void OSUHAEmitFailureTag_(
HA_NOOP_FAILURE_TAG_ID + msgidOffset <= HA_NOOP_FAILURE_TAG_ID ||
HA_NOOP_FAILURE_TAG_ID + msgidOffset > HA_MAX_FAILURE_TAG_ID )
{
+#ifdef ENABLE_MISSED_FAILURE_ITEM_TRACKING
+ FireWall( "SkipFiEvtOutOfRange" );
+#endif
fEmit = fFalse;
}
@@ -214,6 +288,20 @@ void OSUHAEmitFailureTag_(
HA_NOOP_FAILURE_TAG_ID + msgidOffset,
iwsz,
rgwsz );
+
+ AtomicExchangeSet( (ULONG*)&pinstActual->m_grbitHaFailureTags, (ULONG)bitHaPublishedEvent );
+ if ( haTag == HaDbFailureTagCorruption )
+ {
+ AtomicExchangeSet( (ULONG*)&pinstActual->m_grbitHaFailureTags, (ULONG)bitHaPublishedCorruptionTag );
+ }
+ if ( haTag == HaDbFailureTagIoHard )
+ {
+ AtomicExchangeSet( (ULONG*)&pinstActual->m_grbitHaFailureTags, (ULONG)bitHaPublishedIoHardTag );
+ }
+ if ( haTag == HaDbFailureTagLogLogicallyInconsistent )
+ {
+ AtomicExchangeSet( (ULONG*)&pinstActual->m_grbitHaFailureTags, (ULONG)bitHaPublishedLogLogicallyInconsistentTag );
+ }
}
// cleanup
@@ -222,6 +310,8 @@ void OSUHAEmitFailureTag_(
{
pcritInstActual->Leave();
}
+
+ #undef pinst
}
#endif
diff --git a/dev/ese/src/ese/_osu/osustd.hxx b/dev/ese/src/ese/_osu/osustd.hxx
index f05594b9..4ca2abb4 100644
--- a/dev/ese/src/ese/_osu/osustd.hxx
+++ b/dev/ese/src/ese/_osu/osustd.hxx
@@ -7,13 +7,6 @@
#include
#include
-#pragma prefast(push)
-#pragma prefast(disable:26006, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:26007, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28718, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28726, "Dont bother us with tchar, someone else owns that.")
-#include
-#pragma prefast(pop)
#include
#include
#include
diff --git a/dev/ese/src/ese/bbtbuff.cxx b/dev/ese/src/ese/bbtbuff.cxx
new file mode 100644
index 00000000..60144316
--- /dev/null
+++ b/dev/ese/src/ese/bbtbuff.cxx
@@ -0,0 +1,1356 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "std.hxx"
+
+BBTBuff::~BBTBuff()
+{
+ // Caller is responsible for managing latches.
+}
+
+ERR BBTBuff::ErrEnsurePageLatched( SkipListLink link, LATCH latchType )
+{
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( link );
+ return ErrEnsurePageLatched( pgOffset.ipg, latchType );
+}
+
+ERR BBTBuff::ErrEnsurePageLatched( int ipgOffset, LATCH latchType )
+{
+ ERR err = JET_errSuccess;
+ Assert( ipgOffset >= 0 && ipgOffset < Cpg() );
+
+ CSR* pcsr = Pcsr( ipgOffset );
+ if ( pcsr->Latch() != latchType )
+ {
+ switch ( pcsr->Latch() )
+ {
+ case latchNone:
+ {
+ if ( latchType != latchWrite )
+ {
+ CallR( pcsr->ErrGetPage( m_ppib, m_ifmp, m_pcsrBase->Pgno() + ipgOffset, latchType ) );
+ }
+ else
+ {
+ // ErrGetPage() doesn't support getting a write latch directly
+ CallR( pcsr->ErrGetPage( m_ppib, m_ifmp, m_pcsrBase->Pgno() + ipgOffset, latchRIW ) );
+ pcsr->UpgradeFromRIWLatch();
+ }
+ break;
+ }
+
+ case latchReadTouch:
+ EnforceSz( false, "Upgrade from read isn't allowed." );
+ err = ErrERRCheck( JET_errInternalError );
+ break;
+
+ case latchRIW:
+ //Assert( m_latchType == latchRIW );
+ EnforceSz( latchType == latchWrite, "Unsupported latch state transition from RIW latch" );
+ pcsr->UpgradeFromRIWLatch();
+ break;
+
+ case latchWrite:
+ // if the caller asks for RIW, and we have write, it is fine
+ Assert( m_latchType == latchRIW );
+ EnforceSz( latchType == latchRIW, "Unsupported latch state transition from write latch" );
+ break;
+
+ default:
+ EnforceSz( false, "Unsupported current latch state" );
+ err = ErrERRCheck( JET_errInternalError );
+ }
+ }
+
+ Assert( pcsr->Cpage().FBBTBuffPage() );
+ Assert( ( ipgOffset > 0 ) == ( !pcsr->Cpage().FBBTBuffRootPage() ) ); // only the first page is marked with the BBTBuff root flag
+ Assert( m_pcsrBase->Dbtime() == pcsr->Dbtime() );
+ return err;
+}
+
+void BBTBuff::DowngradeLatches()
+{
+ if ( m_latchType == latchRIW || m_latchType == latchReadTouch || m_latchType == latchReadNoTouch )
+ {
+ for ( int i = 0; i < Cpg(); i++ )
+ {
+ CSR* pcsrCurr = Pcsr( i );
+ if ( latchWrite == pcsrCurr->Latch() )
+ {
+ pcsrCurr->Downgrade( m_latchType );
+ }
+ }
+ }
+ else
+ {
+ Assert( m_latchType == latchWrite );
+ }
+}
+
+// Seeks to a particular key.
+// Positions at node(s) based on SeekMode:
+// - SeekMode::LEQ positions at LessThan Or Equal.
+// - SeekMode::LT positions at LessThan.
+// For duplicate nodes, level0 position is at the last (which is the latest) node in the sequence.
+// If all nodes are greater, then positions at the first node, (which would be the oldest node in the sequence).
+// Returns links and nodes at each level (which may belong to different nodes).
+// SeekPos::Prev returns links/nodes to the node before the seeked node (at each level), needed for Delete.
+// Note: SeekPos doesn't modify what key is seeked to, only changes whether returned links point to the seek key,
+// or its predecessors.
+// Returns the comparison value of the seeked key to the nearest node in the order below (based on SeekMode, SeekPos has no effect):
+// 1. If there is a key equal to seeked key, result is 0.
+// 2. Else if LT keys exist, returns < 0.
+// 3. Else if only GT keys exist, returns > 0.
+// SeekMode::LT switches the evaluation order of 1 & 2. If LT exists returns < 0, Else if EQ exists, returns = 0.
+// Note that rgNodes[], rgLinks[] only return what was asked. For example, they will be null if caller asked SeekMode::LT, and we only found GEQ nodes.
+ERR BBTBuff::ErrSeek_(
+ const KEY& key,
+ SeekMode seekMode,
+ SeekPos seekPos,
+ _Out_ int* piResult,
+ _Out_ SkipListLink rgLinks[ MAX_LEVELS ],
+ _Out_ SkipListNode* rgNodes[ MAX_LEVELS ] )
+{
+ ERR err = JET_errSuccess;
+ int cmp = -1; // default value, if the list is empty
+ int cmpLEQ = 1;
+ SkipListNode* pnodePrev = NULL;
+ SkipListNode* pnodeCurr = NULL;
+ SkipListNode* pnodeNext = NULL;
+ SkipListLink linkNodePrev( 0 );
+ SkipListLink linkNodeCurr( 0 );
+ SkipListLink linkNodeNext( 0 );
+ SkipListLinkArray rgLinksCurr = RgSkipListLinksHead( m_pHeader );
+
+ const int comparand = ( seekMode == SeekMode::LT ? 0 :
+ seekMode == SeekMode::LEQ ? 1 :
+ -1 );
+
+ // Search the list for the given key
+ for ( int i = MAX_LEVELS - 1; i >= 0; i-- )
+ {
+ Call( ErrPnodeFromLink_AcqLatch( rgLinksCurr[ i ], &pnodeNext ) );
+ linkNodeNext = rgLinksCurr[ i ];
+ while ( pnodeNext != NULL )
+ {
+ cmp = pnodeNext->CmpKey( key );
+ if ( cmp < comparand )
+ {
+ // Next key is still behind the seeked position
+ // MoveNext
+ pnodePrev = pnodeCurr;
+ pnodeCurr = pnodeNext;
+ linkNodePrev = linkNodeCurr;
+ linkNodeCurr = linkNodeNext;
+ rgLinksCurr = pnodeCurr->RgLinksNext();
+ Call( ErrPnodeFromLink_AcqLatch( rgLinksCurr[ i ], &pnodeNext ) );
+ linkNodeNext = rgLinksCurr[ i ];
+ cmpLEQ = cmp;
+ }
+ else
+ {
+ // Next key is after the seeked position
+ // So move to lower level.
+ break;
+ }
+ }
+
+ // Next key is after the seeked position (or NULL).
+ // Seek point found at the current level.
+ // Now store pointers at the current level for caller.
+ // Null link/pnode means there is no prev node (m_pHeader->rgSkipListLinksHead[i] should still point here)
+
+ // Drill down levels; for all lower levels where
+ // the next node is also the next node at the lower level.
+ for ( i; i >= 1; i-- )
+ {
+ if ( seekPos == SeekPos::Prev )
+ {
+ // Caller gets the prev node at current level.
+ rgLinks[ i ] = linkNodePrev;
+ rgNodes[ i ] = pnodePrev;
+
+ // If we found a match at the current level, we've moved to that node (to seek to the latest in the duplicate sequence).
+ // But to return SeekPos::Prev, we need to find nodes sandwiched between pnodePrev and pnodeCurr at the lower level.
+ // We would've skipped those nodes when we were moving next at a higher level.
+ // To establist the correct prev node at the lower level we are drilling down to,
+ // we have to walk the links at the lower level from the prev node until we land on the curr node.
+ if ( !linkNodeCurr.FNull() )
+ {
+ SkipListLinkArray rgLinksPrev = ( pnodePrev != NULL ? pnodePrev->RgLinksNext() : RgSkipListLinksHead( m_pHeader ) );
+ while ( rgLinksPrev[ i - 1 ] != linkNodeCurr )
+ {
+ // MoveNext (there is a node between prev and curr).
+ linkNodePrev = rgLinksPrev[ i - 1 ];
+ Assert( !linkNodePrev.FNull() ); // we can't walk off the end without hitting pnodeCurr, or the skiplist is ill-formed
+ Call( ErrPnodeFromLink_AcqLatch( linkNodePrev, &pnodePrev ) );
+ rgLinksPrev = pnodePrev->RgLinksNext();
+ }
+ }
+ }
+ else
+ {
+ // Caller gets the current node.
+ rgLinks[ i ] = linkNodeCurr;
+ rgNodes[ i ] = pnodeCurr;
+ }
+
+ if ( linkNodeNext != rgLinksCurr[ i - 1 ] )
+ {
+ // Note that i will be decremented again once by the outer for loop.
+ break;
+ }
+ }
+ }
+
+ // A quirk of the seek loop above, level0 remains to be set.
+ if ( seekPos == SeekPos::Prev )
+ {
+ rgLinks[ 0 ] = linkNodePrev;
+ rgNodes[ 0 ] = pnodePrev;
+ }
+ else
+ {
+ rgLinks[ 0 ] = linkNodeCurr;
+ rgNodes[ 0 ] = pnodeCurr;
+ }
+
+ // if pnodeCurr was found, then it was LEQ to the seek key. Then we should return the LEQ cmp value (as the seek loop would break when a comparison is greater).
+ // else, return cmp. If no node is found, we use cmp (the value of last comparison).
+ *piResult = ( cmpLEQ <= 0 ? cmpLEQ : cmp );
+
+HandleError:
+ return err;
+}
+
+void BBTBuff::AssertLatchedAll( LATCH latchType )
+{
+#ifdef DEBUG
+ for ( int i = 0; i < Cpg(); i++ )
+ {
+ CSR* pcsr = Pcsr( i );
+ Assert( pcsr->Latch() == latchType );
+ }
+#endif
+}
+
+void BBTBuff::AssertReadyForWrite()
+{
+#ifdef DEBUG
+ for ( int i = 0; i < Cpg(); i++ )
+ {
+ CSR* pcsr = Pcsr( i );
+ Assert( pcsr->Latch() == latchWrite );
+ Assert( pcsr->FDirty() );
+ }
+#endif
+}
+
+// Inserts a new node into the list.
+// Duplicate nodes are inserted at the tail of a duplicate sequence.
+SkipListNode* BBTBuff::PnodeInsert_(
+ const BBTBuffChangeContext& changeCtx,
+ SkipListNode* rgNodes[ MAX_LEVELS ],
+ BBTBuffOpcode opcode,
+ const KEY& key,
+ const DATA& data,
+ SkipListNodeFlags flags,
+ bool fDuplicate )
+{
+ AssertReadyForWrite();
+
+ int cbNodeInsert = SkipListNode::Cb( changeCtx.level, key.Cb(), data.Cb() );
+ SkipListLinkArray rgLinksHead = RgSkipListLinksHead( m_pHeader );
+ SkipListLink linkNext0 = ( rgNodes[ 0 ] ? rgNodes[ 0 ]->LinkNext0() : rgLinksHead[ 0 ] );
+ SkipListLink linkNew = changeCtx.linkCurr;
+ int level = changeCtx.level;
+
+ Assert( cbNodeInsert <= CbMaxNodeSize() );
+
+ // Start modifying the header
+ int cbUsed = SkipListLink::Roundup( cbNodeInsert );
+ m_pHeader->le_cbFree -= ( cbUsed + linkNew.ToInt() - m_pHeader->le_ibMicFree->ToInt() ); // count wasted space because of a page switch, too
+ EnforceSz( m_pHeader->le_cbFree >= 0, "BBTBuff: InsertOverflow" );
+ SkipListLink ibMicFree = linkNew;
+ ibMicFree.Inc( cbUsed );
+ m_pHeader->le_ibMicFree = ibMicFree;
+ m_pHeader->le_cNodes++; // The node is now part of the list, officially
+
+ PageOffsetTuple pgOffsetNew = IpgOffsetFromLink( linkNew );
+
+ // In-place initialize the node on the page.
+ SkipListNode* pnodeNew = SkipListNode::Create( PbPage( pgOffsetNew.ipg ) + pgOffsetNew.ibOnPage, level, opcode, key.Cb(), data.Cb() );
+ pnodeNew->SetNodeKey( key );
+ pnodeNew->SetNodeData( data );
+ pnodeNew->SetNodeFlags( flags );
+
+ // Modify the skip list
+ Assert( pnodeNew->IsValid() );
+ pnodeNew->SetLinkPrev0( changeCtx.rgLinksPrev[ 0 ] );
+ SkipListLinkArray rgLinksNew = pnodeNew->RgLinksNext();
+
+ // Adjust links for prev node(s) at each level
+ for ( int i = level; i >= 0; i-- )
+ {
+ SkipListLinkArray rgLinksPrev = rgNodes[ i ] ? rgNodes[ i ]->RgLinksNext() : rgLinksHead;
+ rgLinksNew.SetLink( i, rgLinksPrev[ i ] );
+ rgLinksPrev.SetLink( i, linkNew );
+ }
+
+ // Adjust duplicate flag of the prev node
+ if ( rgNodes[ 0 ] != NULL )
+ {
+ rgNodes[ 0 ]->SetDuplicateNext0( fDuplicate );
+ }
+ else
+ {
+ Assert( fDuplicate == false );
+ }
+
+ // Adjust m_linkPrev0 of the next node
+ if ( !linkNext0.FNull() )
+ {
+ SkipListNode* pnodeNext = PnodeFromLink( linkNext0 );
+ EnforceSz( changeCtx.rgLinksPrev[ 0 ] == pnodeNext->LinkPrev0(), "BBTBuffCorrupt" );
+ pnodeNext->SetLinkPrev0( linkNew );
+
+ // We should never be inserting in the middle of a duplicate sequence.
+ Assert( pnodeNew->CmpKey( pnodeNext->Key() ) < 0 );
+ }
+
+#ifdef DEBUG
+ // Check all the links in the inserted node are valid
+ SkipListNode* pnode = PnodeFromLink( pnodeNew->LinkPrev0() );
+ int cmpWithPrev = ( pnode != NULL ? pnodeNew->CmpKey( pnode->Key() ) : 1 );
+ Assert( cmpWithPrev >= 0 );
+ Assert( fDuplicate == ( cmpWithPrev == 0 ) );
+ Assert( pnode == NULL || pnode->FDuplicateNext0() == fDuplicate );
+
+ for ( int i = 0; i <= pnodeNew->Level(); i++ )
+ {
+ pnode = PnodeFromLink( rgLinksNew[ i ] );
+ if ( pnode != NULL )
+ {
+ Assert( pnode->IsValid() );
+ Assert( pnodeNew->CmpKey( pnode->Key() ) <= 0 );
+ }
+ }
+
+ Assert( !rgLinksHead[ 0 ].FNull() );
+#endif
+
+ return pnodeNew;
+}
+
+// Note: this is a physical delete. Currently, only used to undo a versioned operation during rollback by verstore.
+void BBTBuff::Delete_(
+ BBTBuffChangeContext changeCtx,
+ SkipListNode* rgNodes[ MAX_LEVELS ],
+ const SkipListNode* pnodeToDelete )
+{
+ AssertReadyForWrite();
+ Assert( pnodeToDelete != NULL );
+
+ int level = changeCtx.level;
+ SkipListLink linkDel = changeCtx.linkCurr;
+ SkipListLink linkNext0 = pnodeToDelete->LinkNext0();
+ SkipListNode* pnodeNext0 = PnodeFromLink( linkNext0 );
+
+ // Start modifying the pages
+
+ if ( pnodeNext0 )
+ {
+ pnodeNext0->SetLinkPrev0( pnodeToDelete->LinkPrev0() );
+ }
+
+ // Adjust links for prev node(s) at each level
+ Assert( level == pnodeToDelete->Level() );
+ SkipListLinkArray rgLinksNextToDel = pnodeToDelete->RgLinksNext();
+ for ( int i = pnodeToDelete->Level(); i >= 0; i-- )
+ {
+ SkipListLinkArray rgLinksPrevToDel = ( rgNodes[ i ] != NULL ? rgNodes[ i ]->RgLinksNext() : RgSkipListLinksHead( m_pHeader ) );
+ EnforceSz( rgLinksPrevToDel[ i ] == linkDel, "BBTBuffDelete_CorruptedLinks"); // the link being replaced must point to the node being deleted
+ rgLinksPrevToDel.SetLink( i, rgLinksNextToDel[ i ] );
+ }
+
+ // Fix duplicate flag on the prev node, if the node being deleted is a duplicate of it.
+ if ( rgNodes[ 0 ] != NULL && rgNodes[ 0 ]->FDuplicateNext0() )
+ {
+ // Transfer duplicate flag to the prev node:
+ // - if the node being deleted has a next duplicate, then the prev node also has a next duplicate after deletion.
+ // - if not, then the prev node doesn't either.
+ rgNodes[ 0 ]->SetDuplicateNext0( pnodeToDelete->FDuplicateNext0() );
+ }
+
+ Assert( m_pHeader->le_cNodes > 0 );
+ m_pHeader->le_cNodes--;
+ m_pHeader->le_cbFree += pnodeToDelete->Cb();
+ Assert( m_pHeader->le_cbFree <= CbMax() );
+}
+
+// Deletes a range of nodes, starting from the given link.
+// The range delete operation must start on the oldest node of a duplicate sequence,
+// and end at the latest node of a duplicate sequence.
+// It is an n*log(n) operation, average case.
+void BBTBuff::RangeDelete_( SkipListLink linkFirst, int cNodes )
+{
+ ERR err = JET_errSuccess;
+
+ AssertReadyForWrite();
+ ResetCurr();
+
+ // Check/Prepare for deletion
+ // All modifications are deferred until we know that delete can succeed unconditionally
+ SkipListNode* pnodeFirst = PnodeFromLink( linkFirst );
+ SkipListNode* pnodeCurr = pnodeFirst;
+ SkipListLink linkCurr = linkFirst;
+ KEY keyFirst = pnodeFirst->Key();
+ int cbDeleted = 0;
+
+ // Assert that deleted range doesn't start or end in the middle of a duplicate sequence
+ // Range delete does't fix duplicate flags. It doesn't need to because range delete should
+ // always span duplicate nodes.
+ SkipListNode* pnodeBeforeFirst = PnodeFromLink( pnodeFirst->LinkPrev0() );
+ EnforceSz( pnodeBeforeFirst == NULL || pnodeBeforeFirst->FDuplicateNext0() == false, "RangeDelete()_: PartiallyDeletingDuplicateSequence");
+ Assert( cNodes > 0 );
+
+ // We have to seek to find previous node at each level to remove the node from the skiplist.
+ int result;
+ SkipListLink rgLinksPrev[ MAX_LEVELS ] = {}; // braces zero-initialize the array
+ SkipListNode* rgpNodes[ MAX_LEVELS ] = {};
+ err = ErrSeek_( keyFirst, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Curr, &result, rgLinksPrev, rgpNodes );
+ EnforceSz( result <= 0 && err == JET_errSuccess, "RangeDelete_(): SeekFailed" );
+
+ // Store addresses of the link field of the prev node at each level.
+ // This field needs to be modified to point to the after-last node at each level.
+ //SkipListLink* rgpLinksPrev[ MAX_LEVELS ];
+ //for ( int i = MAX_LEVELS; i >= 0; i-- )
+ //{
+ // rgpLinksPrev[ i ] = ( rgNodes[ i ] != NULL ? rgNodes[ i ]->PrgLinks() + i : &m_pHeader->rgSkipListLinksHead[ i ] );
+ //}
+
+ // Walk all nodes in the range-delete, and move links of the prev node forward step-by-step to after-last,
+ // at each level.
+ SkipListLinkArray rgLinksHead = RgSkipListLinksHead( m_pHeader );
+ SkipListLink rgLinksAfterLast[ MAX_LEVELS ];
+ int iNode = 0;
+
+ // Start from the current node, at each level.
+ for ( int i = 0; i < MAX_LEVELS; i++ )
+ {
+ rgLinksAfterLast[ i ] = ( rgpNodes[ i ] != NULL ? rgpNodes[ i ]->RgLinksNext()[ i ] : rgLinksHead[ i ] );
+ }
+
+ while ( pnodeCurr != NULL )
+ {
+ SkipListLinkArray rgLinksCurr = pnodeCurr->RgLinksNext();
+ for ( int level = pnodeCurr->Level(); level >= 0; level-- )
+ {
+ // Move link to the next node at the current level.
+ Assert( rgLinksAfterLast[ level ] == linkCurr );
+ rgLinksAfterLast[ level ] = rgLinksCurr[ level ];
+ }
+
+ cbDeleted += pnodeCurr->Cb();
+ linkCurr = rgLinksCurr[ 0 ];
+ pnodeCurr = PnodeFromLink( linkCurr );
+ iNode++;
+ if ( iNode >= cNodes )
+ {
+ break;
+ }
+ }
+
+ // Fix the prev link of the after-last node, if it exists.
+ if ( pnodeCurr != NULL )
+ {
+ Assert( pnodeFirst->LinkPrev0() == rgLinksPrev[ 0 ] );
+ pnodeCurr->SetLinkPrev0( rgLinksPrev[ 0 ] );
+ }
+
+ // Fix the next links at all levels to point to the after last nodes.
+ for ( int level = 0; level < MAX_LEVELS; level++ )
+ {
+ ( rgpNodes[ level ] ? rgpNodes[ level ]->RgLinksNext() : rgLinksHead ).SetLink( level, rgLinksAfterLast[ level ] );
+ }
+
+ m_pHeader->le_cNodes -= cNodes;
+ m_pHeader->le_cbFree += cbDeleted;
+
+ Assert( m_pHeader->le_cNodes >= 0 );
+ Assert( m_pHeader->le_cbFree <= CbMax() );
+}
+
+// Seeks to the given key. Favors previous key if no match found.
+// The cursor is placed at LessThanOrEqual, unless all nodes are greater than the key.
+ERR BBTBuff::ErrSeekLEQ( const KEY& key )
+{
+ ERR err = JET_errSuccess;
+ Assert( m_pcsrBase->FLatched() );
+ ResetCurr();
+
+ int result;
+ SkipListLink rgLinks[ MAX_LEVELS ];
+ SkipListNode* rgNodes[ MAX_LEVELS ];
+ Call( ErrSeek_( key, SeekMode::LEQ, SeekPos::Curr, &result, rgLinks, rgNodes ) );
+
+ if ( result == 0 )
+ {
+ Assert( rgNodes[ 0 ]->CmpKey( key ) == 0 );
+ Call( ErrAssertIsLatestInDuplicateSequence( rgNodes[ 0 ] ) );
+
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( rgLinks[ 0 ] );
+ ChangeCurr( pgOffset.ipg, rgNodes[ 0 ] );
+ err = JET_errSuccess;
+ }
+ else if ( rgNodes[ 0 ] != NULL )
+ {
+ // If exact node not found, the Seek loop leaves currency immediately before the seek key
+ Assert( result < 0 );
+ Assert( rgNodes[ 0 ]->CmpKey( key ) < 0 );
+
+ // We've landed on a node immediately before the seek key. The skip list guarantees
+ // that this is the tail of a duplicate sequence.
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( rgLinks[ 0 ] );
+ ChangeCurr( pgOffset.ipg, rgNodes[ 0 ] );
+ err = ErrERRCheck( wrnNDFoundLess );
+ }
+ else if( !RgSkipListLinksHead( m_pHeader )[ 0 ].FNull() )
+ {
+ // If all nodes are greater than the seek key
+ // and there is atleast one node in the list
+ Assert( result > 0 );
+
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( RgSkipListLinksHead( m_pHeader )[ 0 ] );
+ SkipListNode* pnodeCurr = PnodeFromIpgOffset( pgOffset );
+ Assert( pnodeCurr->CmpKey( key ) > 0 );
+
+ if ( !pnodeCurr->FDuplicateNext0() )
+ {
+ ChangeCurr( pgOffset.ipg, pnodeCurr );
+ }
+ else
+ {
+ // We have to walk the list at level0 to get to the tail of the current duplicate sequence.
+ // It is wasted effort if the current node's data/flags are never accessed.
+ // UA_TODO: For simplicity, lets see if this contract makes sense.
+ SkipListLink linkLatest;
+ Call( ErrGetLatestInDuplicateSequence( pnodeCurr, &linkLatest ) );
+
+ if ( !linkLatest.FNull() )
+ {
+ pgOffset = IpgOffsetFromLink( linkLatest );
+ SkipListNode* pnodeLatest = PnodeFromIpgOffset( pgOffset );
+ ChangeCurr( pgOffset.ipg, pnodeLatest );
+ }
+ else
+ {
+ pgOffset = IpgOffsetFromLink( rgLinks[ 0 ] );
+ ChangeCurr( pgOffset.ipg, rgNodes[ 0 ] );
+ }
+ }
+
+ err = ErrERRCheck( wrnNDFoundGreater );
+ }
+ else
+ {
+ // If we aren't leaving currency at some node, BBTBuff must be empty
+ Assert( m_pHeader->le_cNodes == 0 );
+ err = ErrERRCheck( errBBTNodeNotFound );
+ }
+
+HandleError:
+ return err;
+}
+
+// Seeks to a key that is equal to or greater than the given key.
+// Returns errBBTNodeNotFound if all keys are less or the list is empty.
+// Places cursor at the oldest node in the duplicate sequence.
+// WARNING: This is needed to move BBTBuff nodes in an internal split.
+// Don't use for establishing currency.
+ERR BBTBuff::ErrSeekGEQOldest( const KEY& key )
+{
+ ERR err = JET_errSuccess;
+ Assert( m_pcsrBase->FLatched() );
+ ResetCurr();
+
+ int result;
+ SkipListLink rgLinks[ MAX_LEVELS ];
+ SkipListNode* rgNodes[ MAX_LEVELS ];
+ Call( ErrSeek_( key, SeekMode::LT, SeekPos::Curr, &result, rgLinks, rgNodes ) );
+
+ if ( result < 0 && rgNodes[ 0 ] != NULL )
+ {
+ // LT node found, next node (if exists) will be GEQ.
+ Assert( rgNodes[ 0 ]->CmpKey( key ) < 0 );
+ Call( ErrAssertIsLatestInDuplicateSequence( rgNodes[ 0 ] ) );
+
+ if ( !rgNodes[ 0 ]->LinkNext0().FNull() )
+ {
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( rgNodes[ 0 ]->LinkNext0() );
+ SkipListNode* pnodeGEQ = PnodeFromIpgOffset( pgOffset );
+ int cmp = pnodeGEQ->CmpKey( key );
+ Call( ErrAssertIsOldestInDuplicateSequence( pnodeGEQ ) );
+
+ Assert( cmp >= 0 );
+ ChangeCurr( pgOffset.ipg, pnodeGEQ );
+ err = ( cmp > 0 ? ErrERRCheck( wrnNDFoundGreater ) : JET_errSuccess );
+ }
+ else
+ {
+ err = ErrERRCheck( errBBTNodeNotFound );
+ }
+ }
+ else if ( !RgSkipListLinksHead( m_pHeader )[ 0 ].FNull() )
+ {
+ // If all nodes are GEQ than the seek key
+ // and there is atleast one node in the list
+ Assert( result >= 0 );
+
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( RgSkipListLinksHead( m_pHeader )[ 0 ] );
+ SkipListNode* pnodeGEQ = PnodeFromIpgOffset( pgOffset );
+ Assert( result == pnodeGEQ->CmpKey( key ) );
+ ChangeCurr( pgOffset.ipg, pnodeGEQ );
+ err = ( result > 0 ? ErrERRCheck( wrnNDFoundGreater ) : JET_errSuccess );
+ }
+ else
+ {
+ // If we aren't leaving currency at some node, BBTBuff must be empty
+ Assert( m_pHeader->le_cNodes == 0 );
+ err = ErrERRCheck( errBBTNodeNotFound );
+ }
+
+HandleError:
+ return err;
+}
+
+ERR BBTBuff::ErrMoveFirst( SeekFlags fFlags )
+{
+ ERR err = JET_errSuccess;
+ ResetCurr();
+
+ if ( !RgSkipListLinksHead( m_pHeader )[ 0 ].FNull() )
+ {
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( RgSkipListLinksHead( m_pHeader )[ 0 ] );
+ CallR( ErrEnsurePageLatched( pgOffset.ipg, m_latchType ) );
+
+ SkipListNode* pnodeCurr = PnodeFromIpgOffset( pgOffset );
+ if ( fFlags == sfSkipDuplicates )
+ {
+ SkipListLink link( 0 );
+ CallR( ErrGetLatestInDuplicateSequence( pnodeCurr, &link ) );
+ if ( !link.FNull() )
+ {
+ pgOffset = IpgOffsetFromLink( link );
+ pnodeCurr = PnodeFromIpgOffset( pgOffset );
+ }
+ }
+
+ ChangeCurr( pgOffset.ipg, pnodeCurr );
+ return err;
+ }
+ else
+ {
+ return ErrERRCheck( errBBTNodeNotFound );
+ }
+}
+
+// ErrMoveLast is a log(n) operation (average)
+ERR BBTBuff::ErrMoveLast()
+{
+ ERR err = JET_errSuccess;
+ Assert( m_pcsrBase->FLatched() );
+ ResetCurr();
+
+ if ( RgSkipListLinksHead( m_pHeader )[ 0 ].FNull() )
+ {
+ return ErrERRCheck( errBBTNodeNotFound );
+ }
+
+ SkipListNode* pnodeCurr = NULL;
+ SkipListLink linkCurr( 0 );
+ SkipListLinkArray rgLinks = RgSkipListLinksHead( m_pHeader );
+
+ for ( int i = MAX_LEVELS - 1; i >= 0; i-- )
+ {
+ SkipListNode* pnodeNext;
+ Call( ErrPnodeFromLink_AcqLatch( rgLinks[ i ], &pnodeNext ) );
+ while ( pnodeNext != NULL )
+ {
+ // MoveNext at the same level (until we reach the end node at the current level)
+ pnodeCurr = pnodeNext;
+ linkCurr = rgLinks[ i ];
+ rgLinks = pnodeCurr->RgLinksNext();
+ Call( ErrPnodeFromLink_AcqLatch( rgLinks[ i ], &pnodeNext ) );
+ }
+ }
+
+ Assert( pnodeCurr != NULL );
+ Assert( rgLinks[ 0 ].FNull() ); // should be the last node
+ Assert( pnodeCurr->IsValid() );
+
+ {
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( linkCurr );
+ ChangeCurr( pgOffset.ipg, pnodeCurr );
+ }
+
+HandleError:
+ return err;
+}
+
+ERR BBTBuff::ErrMoveNext( SeekFlags fFlags )
+{
+ ERR err = JET_errSuccess;
+ SkipListNode* pnodeCurr = m_pnodeCurr;
+
+ if ( pnodeCurr != NULL )
+ {
+ Assert( pnodeCurr->IsValid() );
+
+ if ( fFlags == sfSkipDuplicates && pnodeCurr->FDuplicateNext0() )
+ {
+ SkipListLink linkLatest( 0 );
+ Call( ErrGetLatestInDuplicateSequence( pnodeCurr, &linkLatest ) );
+
+ Assert( !linkLatest.FNull() );
+ Call( ErrPnodeFromLink_AcqLatch( linkLatest, &pnodeCurr ) );
+ }
+
+ // The node with FDuplicateNext0 == false is the tail of the duplicate sequence
+ // Have to move 1 past it to get the next unique node.
+
+ if ( !pnodeCurr->LinkNext0().FNull() )
+ {
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( pnodeCurr->LinkNext0() );
+ Call( ErrEnsurePageLatched( pgOffset.ipg, m_latchType ) );
+ pnodeCurr = PnodeFromIpgOffset( pgOffset );
+ ChangeCurr( pgOffset.ipg, pnodeCurr );
+
+ if ( fFlags == sfSkipDuplicates )
+ {
+ Call( ErrMoveToLatestInDuplicateSequence() );
+ }
+
+ goto HandleError;
+ }
+ }
+
+ // Currency is only reset if we move beyond the end of the skip list.
+ // For other errors, e.g. IO errors while latching pages, currency stays
+ // where it is.
+ ResetCurr();
+ err = ErrERRCheck( errBBTNodeNotFound );
+
+HandleError:
+ return err;
+}
+
+ERR BBTBuff::ErrMovePrev( SeekFlags fFlags )
+{
+ ERR err = JET_errSuccess;
+ SkipListNode* pnodeCurr = m_pnodeCurr;
+
+ if ( pnodeCurr != NULL )
+ {
+ Assert( pnodeCurr->IsValid() );
+
+ if ( !pnodeCurr->LinkPrev0().FNull() )
+ {
+ SkipListNode* pnodePrev;
+ Call( ErrPnodeFromLink_AcqLatch( pnodeCurr->LinkPrev0(), &pnodePrev ) );
+
+ if ( fFlags == sfSkipDuplicates )
+ {
+ while ( pnodePrev != NULL )
+ {
+ if ( !pnodePrev->FDuplicateNext0() )
+ {
+ ErrAssertIsLatestInDuplicateSequence( pnodePrev );
+ break;
+ }
+
+ pnodeCurr = pnodePrev;
+ Call( ErrPnodeFromLink_AcqLatch( pnodeCurr->LinkPrev0(), &pnodePrev ) );
+ }
+ }
+
+ if ( !pnodeCurr->LinkPrev0().FNull() )
+ {
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( pnodeCurr->LinkPrev0() );
+ pnodeCurr = PnodeFromIpgOffset( pgOffset );
+
+ Assert( pnodeCurr->IsValid() );
+ ChangeCurr( pgOffset.ipg, pnodeCurr );
+ goto HandleError;
+ }
+ else
+ {
+ // We can only get here if MovePrev() on a duplicate set of nodes, that don't have a prev.
+ pnodeCurr->FDuplicateNext0();
+ }
+ }
+ }
+
+ // Currency is only reset if we move beyond the start of the skip list.
+ // For other errors, e.g. IO errors while latching pages, currency stays
+ // where it is.
+ ResetCurr();
+ err = ErrERRCheck( errBBTNodeNotFound );
+
+HandleError:
+ return err;
+}
+
+ERR BBTBuff::ErrGetDuplicate( _Out_ SkipListNode** ppnodeDup, _Inout_ int* piDup )
+{
+ ERR err = JET_errSuccess;
+ SkipListNode* pnodeCurr = m_pnodeCurr;
+
+ if ( pnodeCurr != NULL )
+ {
+ Assert( pnodeCurr->IsValid() );
+
+ int i = 0;
+ for ( i; i < *piDup; i++ )
+ {
+ if ( !pnodeCurr->LinkPrev0().FNull() )
+ {
+ SkipListNode* pnodePrev;
+ Call( ErrPnodeFromLink_AcqLatch( pnodeCurr->LinkPrev0(), &pnodePrev ) );
+ Assert( pnodePrev->IsValid() );
+
+ if ( pnodePrev->FDuplicateNext0() )
+ {
+ Assert( CmpKey( pnodePrev->Key(), pnodeCurr->Key() ) == 0 );
+ pnodeCurr = pnodePrev;
+ continue;
+ }
+ }
+
+ break; // no more duplicates
+ }
+
+ Assert( 0 == m_pnodeCurr->CmpKey( pnodeCurr->Key() ) );
+ *ppnodeDup = pnodeCurr;
+ *piDup = i;
+ }
+ else
+ {
+ Assert( false );
+ Error( ErrERRCheck( errBBTCurrencyLost ) );
+ }
+
+HandleError:
+ return err;
+}
+
+ERR BBTBuff::ErrMoveToLatestInDuplicateSequence()
+{
+ ERR err = JET_errSuccess;
+ SkipListLink linkLatest;
+
+ Assert( m_pnodeCurr && m_pnodeCurr->IsValid() );
+ CallR( ErrGetLatestInDuplicateSequence( m_pnodeCurr, &linkLatest ) );
+
+ if ( !linkLatest.FNull() )
+ {
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( linkLatest );
+ SkipListNode* pnodeCurr = PnodeFromIpgOffset( pgOffset ); // should already be latched
+ ChangeCurr( pgOffset.ipg, pnodeCurr );
+ }
+
+ return err;
+}
+
+// Moves to the most recent duplicate node of the given node,
+// which is the last node of the current duplicate sequence.
+// Moves forward through the sequence to find the tail of the duplicate sequence.
+// Returns a null link if the current node is already the latest node in the duplicate sequence.
+// NOTE: The caller is responsible for releasing latches !
+ERR BBTBuff::ErrGetLatestInDuplicateSequence( SkipListNode* pnodeCurr, _Out_ SkipListLink* plinkLatestDup )
+{
+ ERR err = JET_errSuccess;
+ SkipListLink linkCurr( 0 );
+ SkipListNode* pnodeNext;
+
+ while ( pnodeCurr->FDuplicateNext0() )
+ {
+ CallR( ErrPnodeFromLink_AcqLatch( pnodeCurr->LinkNext0(), &pnodeNext ) );
+ Assert( pnodeNext != NULL );
+ linkCurr = pnodeCurr->LinkNext0();
+ pnodeCurr = pnodeNext;
+ }
+
+ *plinkLatestDup = linkCurr;
+ return err;
+}
+
+ERR BBTBuff::ErrAssertIsLatestInDuplicateSequence( const SkipListNode* pnode )
+{
+ ERR err = JET_errSuccess;
+
+#ifdef DEBUG
+ // Assert that the given node is at the tail of a duplicate sequence.
+ // That is, it's the latest node in the duplicate sequence.
+ Assert( pnode->FDuplicateNext0() == false );
+
+ SkipListNode* pnodeNext;
+ CallR( ErrPnodeFromLink_AcqLatch( pnode->LinkNext0(), &pnodeNext ) );
+ if ( pnodeNext != NULL )
+ {
+ Assert( pnode->CmpKey( pnodeNext->Key() ) < 0 );
+ }
+#endif
+
+ return err;
+}
+
+ERR BBTBuff::ErrAssertIsOldestInDuplicateSequence( const SkipListNode* pnode )
+{
+ ERR err = JET_errSuccess;
+
+#ifdef DEBUG
+ SkipListNode* pnodePrev;
+ CallR( ErrPnodeFromLink_AcqLatch( pnode->LinkPrev0(), &pnodePrev ) );
+ if ( pnodePrev != NULL )
+ {
+ Assert( !pnodePrev->FDuplicateNext0() );
+ Assert( pnodePrev->CmpKey( pnode->Key() ) < 0 );
+ }
+#endif
+
+ return err;
+}
+
+#define ErrorIf( err, expr ) if ( expr ) { Error( ErrERRCheck( err ) ); }
+
+ERR BBTBuff::ErrValidate()
+{
+ ERR err = JET_errSuccess;
+ KEY rgKeyPrev[ MAX_LEVELS ];
+ SkipListLink rgLinksPrev[ MAX_LEVELS ];
+ SkipListNode* pnodeCurr;
+ SkipListLink linkPrev( 0 );
+ int cNodes = 0;
+ bool fDuplicatePrev = false;
+
+ // Check header.
+ ErrorIf( JET_errBBTBuffCorrupted, m_pHeader->nVersion != bbtvInitial );
+ ErrorIf( JET_errBBTBuffCorrupted, m_pHeader->cMaxPages != PFormat()->cpgInBBTBuff );
+
+ Call( ErrLatchAll() );
+
+ // Check DBTIMEs on each page of the BBTBuff. They should be the same.
+ DBTIME dbtime = m_pcsrBase->Dbtime();
+ for ( int i = 0; i < Cpg() - 1; i++ )
+ {
+ ErrorIf( JET_errBBTBuffCorrupted, dbtime != m_rgcsrLatched[ i ].Dbtime() );
+ }
+
+ // Start from header's skiplist links.
+ {
+ memset( rgKeyPrev, 0, sizeof( rgKeyPrev ) );
+ SkipListLinkArray rgLinksHead = RgSkipListLinksHead( m_pHeader );
+ for ( int i = 0; i < MAX_LEVELS; i++ )
+ {
+ rgLinksPrev[ i ] = rgLinksHead[ i ];
+ ErrorIf( JET_errBBTBuffCorrupted, rgLinksPrev[ i ].ToInt() >= m_pHeader->le_ibMicFree->ToInt() );
+ }
+ }
+
+ // Iterate over all nodes in the skiplist.
+ pnodeCurr = PnodeFromLink( rgLinksPrev[ 0 ] );
+ while ( pnodeCurr != NULL )
+ {
+ ErrorIf( JET_errBBTNodeCorrupted, !pnodeCurr->IsValid() );
+ ErrorIf( JET_errBBTNodeCorrupted, pnodeCurr->Opcode() >= bbtOpUpsert ); // last valid opcode currently
+
+ SkipListLink linkCurr = rgLinksPrev[ 0 ];
+ KEY keyCurr = pnodeCurr->Key();
+
+ // Level0 checks.
+ if ( fDuplicatePrev )
+ {
+ ErrorIf( JET_errBBTBuffCorrupted, CmpKey( rgKeyPrev[ 0 ], keyCurr ) != 0 );
+ }
+ else
+ {
+ ErrorIf( JET_errBBTBuffCorrupted, CmpKey( rgKeyPrev[ 0 ], keyCurr ) >= 0 );
+ }
+
+ // If node is in order but the prev link of this node doesn't point to the prev node in sequence,
+ // assume this node's prev link is corrupt (hence JET_errBBTNodeCorrupted).
+ ErrorIf( JET_errBBTNodeCorrupted, linkPrev != pnodeCurr->LinkPrev0() );
+
+ // Check that same node should occupy every level of the prev link array upto the curr node level.
+ for ( int i = 1; i <= pnodeCurr->Level(); i++ )
+ {
+ ErrorIf( JET_errBBTBuffCorrupted, linkCurr != rgLinksPrev[ i ] );
+ }
+ // Since we've already checked keyCurr and link array, this means that rgKeyPrev[ level ] <= keyCurr for each level.
+
+ cNodes++;
+ ErrorIf( JET_errBBTBuffCorrupted, cNodes > m_pHeader->le_cNodes );
+
+ // Check if current node protrudes into the unused region of the bbt buffer.
+ int ibEndOfNode = SkipListLink::Roundup( linkCurr.ToInt() + pnodeCurr->Cb() );
+ ErrorIf( JET_errBBTBuffCorrupted, ibEndOfNode > m_pHeader->le_ibMicFree->ToInt() );
+
+ // Move state to next node.
+ SkipListLinkArray rgLinks = pnodeCurr->RgLinksNext();
+ for ( int i = 0; i <= pnodeCurr->Level(); i++ )
+ {
+ rgLinksPrev[ i ] = rgLinks[ i ];
+ rgKeyPrev[ i ] = keyCurr;
+
+ // Check links of the curr node.
+ ErrorIf( JET_errBBTNodeCorrupted, rgLinksPrev[ i ].ToInt() >= m_pHeader->le_ibMicFree->ToInt() );
+ }
+
+ linkPrev = linkCurr;
+ fDuplicatePrev = pnodeCurr->FDuplicateNext0();
+ pnodeCurr = PnodeFromLink( rgLinksPrev[ 0 ] );
+ }
+
+ // All links should point to null at the end.
+ for ( int i = 0; i < MAX_LEVELS; i++ )
+ {
+ ErrorIf( JET_errBBTBuffCorrupted, !rgLinksPrev[ i ].FNull() );
+ }
+
+HandleError:
+ return err;
+}
+
+#undef ErrorIf
+
+void BBTBuff::Load(
+ _In_ PIB* ppib,
+ IFMP ifmp,
+ _In_ CSR* pcsr,
+ _In_ CSRHeapArray& rgcsrBBT,
+ BBTBuffHeader* pbbtbHeader,
+ LATCH latchType )
+{
+ Assert( latchType == pcsr->Latch() );
+ Assert( pbbtbHeader->nVersion == bbtvInitial );
+
+ // Make sure that bbtbuff isn't already loaded
+ Assert( m_ppib == NULL && m_ifmp == ifmpNil && m_pHeader == NULL && m_pcsrBase == NULL );
+
+ EnforceSz( m_cMaxPages == 0 || m_cMaxPages == pbbtbHeader->cMaxPages, "BBTBuffInvalidMaxPages" );
+ m_ifmt = (BYTE) IBBTBuffFormatForPage( g_cbPage );
+ Assert( BBTBUFF_FORMAT_CONSTANTS[ m_ifmt ].cpgInBBTBuff < 256 );
+
+ m_ppib = ppib;
+ m_ifmp = ifmp;
+ m_pHeader = pbbtbHeader;
+ m_latchType = latchType;
+ m_cMaxPages = m_pHeader->cMaxPages;
+
+ Assert( rgcsrBBT != NULL );
+ Assert( rgcsrBBT.CItems() == m_pHeader->cMaxPages - 1 );
+
+ m_pcsrBase = pcsr;
+ m_rgcsrLatched = rgcsrBBT;
+
+ // BBTBuff doesn't insert tags/ilines. It uses the page data space as one big buffer.
+ // But to keep CPAGE checks happy, we can't reclaim the reserved tag.
+ m_cbPageDataMax = CPAGE::CbPageDataMaxNoInsert( g_cbPage );
+
+ m_pnodeCurr = NULL;
+ m_ipgCurr = -1;
+
+ EnforceSz( FIsHeaderValid(), "BBTBuffInvalidHeader" );
+}
+
+void BBTBuff::Unload()
+{
+ ResetCurr();
+ m_ppib = NULL;
+ m_ifmp = ifmpNil;
+ m_pHeader = NULL;
+ m_pcsrBase = NULL;
+ m_rgcsrLatched = NULL;
+}
+
+bool BBTBuff::FIsHeaderValid() const
+{
+ BYTE* pbHdr = (BYTE*) m_pHeader;
+ return m_pHeader != NULL &&
+ pbHdr > PbPage( 0 ) &&
+ pbHdr + sizeof( BBTBuffHeader ) < PbPage( 0 ) + g_cbPage &&
+ m_pHeader->nVersion == bbtvInitial &&
+ m_pHeader->cMaxPages == PFormat()->cpgInBBTBuff &&
+ m_pHeader->le_cbFree >= 0 && m_pHeader->le_cbFree <= CbMax() &&
+ m_pHeader->le_cNodes >= 0 && m_pHeader->le_cNodes < CbMax() / sizeof( SkipListNode );
+}
+
+bool BBTBuff::FLoaded() const
+{
+ Assert( m_pHeader == NULL || FIsHeaderValid() );
+ return ( m_pHeader != NULL );
+}
+
+ERR BBTBuff::ErrLatchAll()
+{
+ ERR err = JET_errSuccess;
+
+ Assert( m_pcsrBase->FLatched() );
+ for ( int i = 0; i < Cpg(); i++ )
+ {
+ CallR( ErrEnsurePageLatched( i, m_latchType ) );
+ }
+
+ return err;
+}
+
+ERR BBTBuff::ErrWriteLatchAll()
+{
+ ERR err = JET_errSuccess;
+
+ if ( latchRIW == m_pcsrBase->Latch() )
+ {
+ m_pcsrBase->UpgradeFromRIWLatch();
+ }
+ else if ( latchWrite != m_pcsrBase->Latch() )
+ {
+ return ErrERRCheck( errBFLatchConflict );
+ }
+
+ for ( int i = 1; i < Cpg(); i++ )
+ {
+ CallR( ErrEnsurePageLatched( i, latchWrite ) );
+ }
+
+ m_latchType = latchWrite;
+ return err;
+}
+
+void BBTBuff::Downgrade( LATCH latchType )
+{
+ Assert( m_latchType == latchWrite );
+ Assert( latchType == latchReadTouch || latchType == latchRIW );
+ m_latchType = latchType;
+
+ DowngradeLatches();
+}
+
+ERR BBTBuff::ErrSetCurrNodeFromLink( SkipListLink link )
+{
+ ERR err = JET_errSuccess;
+ Assert( m_pcsrBase->FLatched() );
+
+ if ( link.FNull() )
+ {
+ ResetCurr();
+ return ErrERRCheck( errBBTNodeNotFound );
+ }
+
+ PageOffsetTuple pgOffset = IpgOffsetFromLink( link );
+ CallR( ErrEnsurePageLatched( pgOffset.ipg, m_latchType ) );
+
+ SkipListNode* pnode = PnodeFromIpgOffset( pgOffset );
+ Assert( pnode->IsValid() );
+ ChangeCurr( pgOffset.ipg, pnode );
+ return err;
+}
+
+bool BBTBuff::FCanInsert( const KEY& key, const DATA& data, _Out_ int* pcbReq )
+{
+ // Check for level0 node. Insertion code will first try with a random level, then fallback to level0.
+ int cbNodeInsert = SkipListLink::Roundup( SkipListNode::Cb( 0, key.Cb(), data.Cb() ) );
+ // UA_TODO: we can still hit this because BBTBuff nodes have a minimum 8-byte overhead vs 6-bytes for BTs.
+ EnforceSz( cbNodeInsert <= CbMaxNodeSize(), "BBTBuff MaxNodeSizeExceeded" );
+
+ if ( pcbReq )
+ {
+ *pcbReq = cbNodeInsert;
+ }
+
+ Assert( CbMax() - m_pHeader->le_ibMicFree->ToInt() >= 0 );
+ if ( cbNodeInsert <= CbMax() - m_pHeader->le_ibMicFree->ToInt() )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void BBTBuff::InitBBTBuffHeader( _Out_ BBTBuffHeader* pbbtbHeader, _In_ int cMaxPages )
+{
+ memset( pbbtbHeader, 0, sizeof( BBTBuffHeader ) );
+
+ pbbtbHeader->nVersion = bbtvInitial;
+
+ Assert( cMaxPages < 256 );
+ pbbtbHeader->cMaxPages = (BYTE) cMaxPages;
+
+ pbbtbHeader->le_ibMicFree = SkipListLink::FromInt( sizeof( BBTBuffHeader ) ); // leave space for the header
+ pbbtbHeader->le_cbFree = CbMax() - pbbtbHeader->le_ibMicFree->ToInt();
+
+ // Fields zero-ed out:
+ // count
+ // rgSkipListLinksHead[]
+}
+
+void BBTBuff::InitBBTBuffRoot( FUCB* pfucb, CSR* pcsr )
+{
+ const BBTBuffFormat* pFormat = BBTBuff::PBBTBuffFormatForPage( g_cbPage );
+
+ // Init BBTBuff root page (base page, not tree root)
+ //
+ Assert( latchWrite == pcsr->Latch() );
+ Assert( pcsr->FDirty() );
+ pcsr->SetILine( 0 );
+
+ Assert( 0 == pcsr->Cpage().Clines() ); // must not have any data on the page
+ Assert( pcsr->Cpage().CbPageFree() > pFormat->cbBBTRoot );
+
+ // All of these flags should be set
+ const ULONG fReqPageFlagsRoot = ( CPAGE::fPageBBTBuff | CPAGE::fPageBBTBuffRoot );
+ Assert( fReqPageFlagsRoot == ( fReqPageFlagsRoot & pcsr->Cpage().FFlags() ) );
+
+ int cb = sizeof( NodeResvTag ) + pFormat->cbBBTRoot;
+ INT itag = INDAddReservedTag( pfucb, pcsr, rtidBBTBuff, cb, 0 );
+
+ // The second reserved tag on the page must be the BBTBuff root tag.
+ EnforceSz( itag == itagReservedBBTBuffRoot, "InitBBTBuffRoot: BadReservedTag" );
+
+ LINE line;
+ GetBBTBuffRoot( *pcsr, &line );
+ BBTBuff::InitBBTBuffHeader( PBBTHeader( line ), pFormat->cpgInBBTBuff );
+}
+
+void BBTBuff::InitBBTBuffNonRoot( CSR* pcsr )
+{
+ const INT cbPageDataMax = (INT) pcsr->Cpage().CbPageDataMax();
+
+ // Init non-root BBTBuff pages
+ //
+ Assert( latchWrite == pcsr->Latch() );
+ Assert( pcsr->FDirty() );
+
+ const ULONG fReqPageFlags = CPAGE::fPageBBTBuff;
+ Assert( fReqPageFlags == ( fReqPageFlags & pcsr->Cpage().FFlags() ) );
+
+ pcsr->Cpage().ResetReservedTag( 0, cbPageDataMax, 0 ); // take over external header tag
+}
+
+void BBTBuff::GetBBTBuffRoot( const CSR& csr, LINE* pline )
+{
+ Assert( csr.FLatched() );
+ Assert( csr.Cpage().FBBTBuffRootPage() ); // can only be a root or internal page
+
+ csr.Cpage().GetPtrReservedTag( itagReservedBBTBuffRoot, pline );
+ NodeResvTag* pResvTag = (NodeResvTag*) pline->pv;
+
+ Assert( rtidBBTBuff == pResvTag->resvTagId );
+ Assert( pline->cb == sizeof( NodeResvTag ) + (ULONG) BBTBuff::PBBTBuffFormatForPage( g_cbPage )->cbBBTRoot );
+}
+
+BBTBuffHeader* BBTBuff::PBBTHeader( const LINE& line )
+{
+ NodeResvTag* pResvTag = (NodeResvTag*) line.pv;
+ Assert( rtidBBTBuff == pResvTag->resvTagId );
+ Assert( line.cb == sizeof( NodeResvTag ) + (ULONG) BBTBuff::PBBTBuffFormatForPage( g_cbPage )->cbBBTRoot );
+ return (BBTBuffHeader*) pResvTag->rgb;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Debug helpers
+
+std::string DumpBBTBuffHeader( const BBTBuffHeader* pHeader )
+{
+ std::string str = "";
+ char buff[ 256 ];
+
+ sprintf_s( buff, FORMAT_UINT( BBTBuffHeader, pHeader, nVersion, 0 ) );
+ str.append( buff );
+
+ sprintf_s( buff, FORMAT_UINT( BBTBuffHeader, pHeader, cMaxPages, 0 ) );
+ str.append( buff );
+
+ sprintf_s( buff, FORMAT_( BBTBuffHeader, pHeader, le_ibMicFree, 0 ) );
+ str.append( buff );
+ sprintf_s( buff, "%d (0x%X)\n", pHeader->le_ibMicFree->ToInt(), pHeader->le_ibMicFree->ToInt() );
+ str.append( buff );
+
+ sprintf_s( buff, FORMAT_INT( BBTBuffHeader, pHeader, le_cbFree, 0 ) );
+ str.append( buff );
+
+ sprintf_s( buff, FORMAT_UINT( BBTBuffHeader, pHeader, le_cNodes, 0 ) );
+ str.append( buff );
+
+ return str;
+}
+
+std::string DumpBBTBuff( const BBTBuff& bbtBuff, INT level, INT ib /* = 0 */ )
+{
+ std::string str;
+ char buff[ 256 ];
+
+ str.reserve( 4096 ); // just get some initial size going
+
+ int pgnoFirst = bbtBuff.Pcsr( 0 )->Pgno();
+ int pgnoLast = bbtBuff.Pcsr( bbtBuff.Cpg() - 1 )->Pgno();
+ sprintf_s( buff, "BBT Buffer Superpage spanning pgnos [%d (0x%x), %d (0x%x)]\n\n", pgnoFirst, pgnoFirst, pgnoLast, pgnoLast );
+ str.append( buff );
+ str.append( DumpBBTBuffHeader( bbtBuff.m_pHeader ) );
+ str += '\n';
+
+ __try
+ {
+ SkipListLink linkCurr = ( ib == 0 ) ? RgSkipListLinksHead( bbtBuff.m_pHeader )[ 0 ] : SkipListLink::FromInt( ib );
+ while ( !linkCurr.FNull() )
+ {
+ const SkipListNode* pnodeCurr = bbtBuff.PnodeFromLink( linkCurr );
+ str.append( bbtBuff.PnodeCurr() == pnodeCurr ? "-->" : " " );
+ str.append( level == 0 && pnodeCurr->FDuplicateNext0() ? "D " : " " );
+ str.append( pnodeCurr->Key().ToString() );
+ sprintf_s( buff, ", Op( %d ), Level( %d ), Cb( %d ), Data( %d ) ",
+ pnodeCurr->Opcode(),
+ pnodeCurr->Level(),
+ pnodeCurr->Cb(),
+ pnodeCurr->CbData() );
+ str.append( buff );
+
+ SkipListLink linkNext;
+ if ( level == 0 )
+ {
+ linkNext = pnodeCurr->LinkNext0();
+ sprintf_s( buff, "Link( %d ), Prev0( %d ), Next0( %d ): ", linkCurr.ToInt(), pnodeCurr->LinkPrev0().ToInt(), linkNext.ToInt() );
+ }
+ else
+ {
+ int maxLevel = min( level, pnodeCurr->Level() );
+ linkNext = pnodeCurr->RgLinksNext()[ maxLevel ];
+ sprintf_s( buff, "Link( %d ), Next%d( %d ): ", linkCurr.ToInt(), maxLevel, linkNext.ToInt() );
+ }
+ str.append( buff );
+
+ DATA data = pnodeCurr->Data();
+ bool fLargeData = data.Cb() > 16;
+ data.SetCb( fLargeData ? 16 : data.Cb() );
+ str.append( data.ToString() );
+ str.append( fLargeData ? "...\n" : "\n" );
+
+ linkCurr = linkNext;
+ }
+ }
+ __except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ sprintf_s( buff, "\n ---- Encountered expcetion: 0x%x ----\n", GetExceptionCode() );
+ str.append( buff );
+ }
+
+ return str;
+
+// Force includes the function even if there are no calls to it.
+// This allows the function to be available for debugging in VS.
+#pragma comment(linker, "/include:" __FUNCDNAME__)
+}
+
diff --git a/dev/ese/src/ese/bbtbuff_test.cxx b/dev/ese/src/ese/bbtbuff_test.cxx
new file mode 100644
index 00000000..78c918b5
--- /dev/null
+++ b/dev/ese/src/ese/bbtbuff_test.cxx
@@ -0,0 +1,1151 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "std.hxx"
+#include "bbtbuffwriter.hxx"
+
+#ifndef ENABLE_JET_UNIT_TEST
+#error This file should only be compiled with the unit tests!
+#endif // !ENABLE_JET_UNIT_TEST
+
+#define CHECK_CALL( expr ) CHECK( JET_errSuccess == ( expr ) )
+
+class BBTBuffTrxLog_Test : public IBBTBuffTrxLog
+{
+public:
+ ERR m_returnErr = JET_errSuccess; // error to return from trx log for testing
+
+ BBTBuffTrxLog_Test( BBTBuff* pbbtbuff ) : IBBTBuffTrxLog( pbbtbuff )
+ {}
+
+ ERR ErrLogInsert(
+ const BBTBuffChangeContext& changeCtx,
+ BBTBuffOpcode opcode,
+ const KEY& key,
+ const DATA& data,
+ SkipListNodeFlags flags )
+ {
+ return m_returnErr;
+ }
+
+ ERR ErrLogDelete(
+ const BBTBuffChangeContext& changeCtx,
+ const SkipListNode* pnodeDel )
+ {
+ return m_returnErr;
+ }
+
+ ERR ErrLogRangeDelete(
+ DBTIME dbtimeBefore,
+ DBTIME dbtimeCurr,
+ SkipListLink linkFirst,
+ int cNodes )
+ {
+ return m_returnErr;
+ }
+
+ ERR ErrLogMergeAndDel(
+ DBTIME dbtimeBefore,
+ DBTIME dbtimeCurr,
+ const SkipListNode** rgNodesMerged,
+ SkipListLink* rgLinksDel,
+ int cNodesMerged,
+ int cNodesDel,
+ SkipListLink linkIbMergeStart )
+ {
+ return m_returnErr;
+ }
+};
+
+using BBTBuffWriter_Test = BBTBuffWriter;
+
+class BBTBuffTestFixture
+{
+public:
+ CSRHeapArray m_rgcsr;
+ BBTBuff m_bbtBuff;
+ BBTBuffTrxLog_Test m_bbtBuffTrxLogger;
+ BBTBuffWriter_Test m_bbtBuffWriter;
+ BBTBuffHeader* m_pbbtHeader;
+
+ BBTBuffTestFixture() :
+ m_rgcsr( CSRHeapArray::MakeArray( BBTBuff::PBBTBuffFormatForPage( g_cbPage )->cpgInBBTBuff ) ),
+ m_bbtBuffTrxLogger( &m_bbtBuff ),
+ m_bbtBuffWriter( &m_bbtBuff, &m_bbtBuffTrxLogger )
+ {
+ m_rgcsr[ 0 ].LoadNewTestPage( g_cbPage, ifmpNil );
+ m_rgcsr[ 0 ].Cpage().SetFlags( m_rgcsr[ 0 ].Cpage().FFlags() | CPAGE::fPageBBTBuffRoot | CPAGE::fPageBBTBuff );
+ BBTBuff::InitBBTBuffRoot( NULL, &m_rgcsr[ 0 ] );
+
+ for ( int i = 1; i < m_rgcsr.CItems(); i++ )
+ {
+ m_rgcsr[ i ].LoadNewTestPage( g_cbPage, ifmpNil, m_rgcsr[ 0 ].Pgno() + i );
+ m_rgcsr[ i ].Cpage().SetFlags( m_rgcsr[ i ].Cpage().FFlags() | CPAGE::fPageBBTBuff );
+ BBTBuff::InitBBTBuffNonRoot( &m_rgcsr[ i ] );
+ }
+
+ LINE line;
+ BBTBuff::GetBBTBuffRoot( m_rgcsr[ 0 ], &line );
+ m_pbbtHeader = BBTBuff::PBBTHeader( line );
+ m_bbtBuff.Load( NULL, ifmpNil, &m_rgcsr[ 0 ], CSRHeapArray( m_rgcsr.Subarray( 1 ) ), m_pbbtHeader, latchWrite );
+ }
+
+ ERR ErrHotpointInsert( int iKeyStep, int cHotpoints, int level = -1 )
+ {
+ ERR err;
+ BigEndian be_key = iKeyStep;
+ int iData = 0;
+ KEY key;
+ DATA data;
+
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+ data.Nullify();
+ data.SetPv( &iData );
+ data.SetCb( sizeof( iData ) );
+
+ m_bbtBuffTrxLogger.m_dbtimeCoordinated = dbtimeStart + 10;
+ CallR( m_bbtBuffWriter.ErrUpgradeToWriteMode() );
+
+ int iKeyBound = ( cHotpoints + 1 ) * iKeyStep;
+ do
+ {
+ m_bbtBuff.SetLevelSeed( level ); // override next node level for testing (-1 means no override)
+ err = m_bbtBuffWriter.ErrInsert( bbtOpInsert, key, data, fSLNNone );
+ be_key = be_key % iKeyBound;
+ be_key += iKeyStep;
+ iData += ( be_key == iKeyStep ? 1 : 0 ); // increment data on every wrap-around
+ } while ( err == JET_errSuccess );
+
+ return err;
+ }
+
+ ERR ErrRandomInsert( int count = INT_MAX )
+ {
+ ERR err;
+ BigEndian be_key = 0;
+ int iData = 0;
+ KEY key;
+ DATA data;
+
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+ data.Nullify();
+ data.SetPv( &iData );
+ data.SetCb( sizeof( iData ) );
+
+ m_bbtBuffTrxLogger.m_dbtimeCoordinated = dbtimeStart + 10;
+ CallR( m_bbtBuffWriter.ErrUpgradeToWriteMode() );
+
+ int cInserted = 0;
+ do
+ {
+ be_key = rand();
+ err = m_bbtBuffWriter.ErrInsert( bbtOpInsert, key, data, fSLNNone );
+ iData += 10;
+ cInserted++;
+ } while ( err == JET_errSuccess && cInserted < count );
+
+ return err;
+ }
+
+ ERR ErrDeleteKey( int ikey )
+ {
+ ERR err;
+ BigEndian be_key = ikey;
+ KEY key;
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+
+ while ( JET_errSuccess == ( err = m_bbtBuffWriter.ErrDelete( key ) ) )
+ {}
+
+ return err == errBBTNodeNotFound ? JET_errSuccess : err;
+ }
+
+ template
+ ERR ErrKeyForEachOldestToLatest( int ikey, TFunc func )
+ {
+ ERR err;
+ BigEndian be_key = ikey;
+ KEY key;
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+
+ CallR( m_bbtBuff.ErrSeekGEQOldest( key ) );
+ do
+ {
+ func( m_bbtBuff.PnodeCurr() );
+ }
+ while ( m_bbtBuff.PnodeCurr()->FDuplicateNext0() && JET_errSuccess == ( err = m_bbtBuff.ErrMoveNext( BBTBuff::sfAllowDuplicates ) ) );
+
+ return err;
+ }
+};
+
+// ================================================================
+JETUNITTEST( BBTBuff, DmlBasic )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ BigEndian be_key = 42;
+ int iData = 10;
+ KEY key;
+ DATA data;
+
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+ data.Nullify();
+ data.SetPv( &iData );
+ data.SetCb( sizeof( iData ) );
+
+ tf.m_bbtBuffTrxLogger.m_dbtimeCoordinated = dbtimeStart + 10;
+
+ for ( int i = 0; i < 10; i++ )
+ {
+ CHECK_CALL( tf.m_bbtBuffWriter.ErrInsert( bbtOpInsert, key, data, fSLNNone ) );
+ be_key++;
+ iData += 10;
+ }
+
+ be_key = 45;
+ iData = 40;
+ CHECK_CALL( tf.m_bbtBuff.ErrSeekLEQ( key ) );
+ CHECK( 0 == CmpData( tf.m_bbtBuff.PnodeCurr()->Data(), data ) );
+
+ CHECK_CALL( tf.m_bbtBuffWriter.ErrDelete( key ) );
+ CHECK( wrnNDFoundLess == tf.m_bbtBuff.ErrSeekLEQ( key ) );
+
+ be_key = 44;
+ iData = 30;
+ CHECK( 0 == tf.m_bbtBuff.PnodeCurr()->CmpKey(key ) );
+ CHECK( 0 == CmpData( tf.m_bbtBuff.PnodeCurr()->Data(), data ) );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, Append )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ BigEndian be_key = 0;
+ int iData = 0;
+ KEY key;
+ DATA data;
+
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+ data.Nullify();
+ data.SetPv( &iData );
+ data.SetCb( sizeof( iData ) );
+
+ tf.m_bbtBuffTrxLogger.m_dbtimeCoordinated = dbtimeStart + 10;
+ CHECK_CALL( tf.m_bbtBuffWriter.ErrUpgradeToWriteMode() );
+
+ ERR err = JET_errSuccess;
+ do
+ {
+ err = tf.m_bbtBuffWriter.ErrInsert( bbtOpInsert, key, data, fSLNNone );
+ CHECK( err == JET_errSuccess || err == errBBTBuffFull );
+ be_key++;
+ iData += 10;
+ }
+ while ( err == JET_errSuccess );
+
+ be_key--;
+ wprintf( L"%d nodes inserted. ", (int) be_key );
+ CHECK( tf.m_pbbtHeader->le_cNodes == (int) be_key );
+ CHECK( tf.m_pbbtHeader->le_ibMicFree->ToInt() + SkipListNode::Cb( 0, key.Cb(), data.Cb() ) > tf.m_bbtBuff.CbMax() );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, HotpointInsert )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16 ) );
+
+ wprintf( L"%d nodes inserted. ", (INT) tf.m_pbbtHeader->le_cNodes );
+ CHECK( tf.m_pbbtHeader->le_ibMicFree->ToInt() + SkipListNode::Cb( 0, sizeof( int ), sizeof( int ) ) > tf.m_bbtBuff.CbMax() );
+}
+
+JETUNITTEST( BBTBuff, InsertMaxNodeSize )
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ KEY key;
+ DATA data;
+ unique_ptr pkey( new BYTE[ cbKeyMostMost ] );
+ unique_ptr pdata( new BYTE[ g_cbPage ] );
+ int cbMaxSize = tf.m_bbtBuff.CbMaxNodeSize() - SkipListNode::Cb( 0, 0, 0 );
+
+ memset( pkey.get(), 0xdada, cbKeyMostMost);
+ memset( pdata.get(), 0xd0d0, g_cbPage);
+
+ key.Nullify();
+ key.suffix.SetPv( pkey.get() );
+ key.suffix.SetCb( cbKeyMostMost );
+ data.Nullify();
+ data.SetPv( pdata.get() );
+ data.SetCb( cbMaxSize - cbKeyMostMost );
+
+ tf.m_bbtBuffTrxLogger.m_dbtimeCoordinated = dbtimeStart + 10;
+ CHECK_CALL( tf.m_bbtBuffWriter.ErrUpgradeToWriteMode() );
+ CHECK_CALL( tf.m_bbtBuffWriter.ErrInsert( bbtOpInsert, key, data, fSLNNone ) );
+
+ // Insert 1 byte more than max supported node.
+ // Should enforce.
+ bool fEnforce = false;
+ data.SetCb( data.Cb() + 1 );
+
+ __try
+ {
+ tf.m_bbtBuffWriter.ErrInsert( bbtOpInsert, key, data, fSLNNone );
+ }
+ __except ( JetTestEnforceSEHException::Filter( GetExceptionInformation() ) )
+ {
+ fEnforce = true;
+ JetTestEnforceSEHException::Cleanup();
+ }
+
+ CHECK( fEnforce );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, ScanForward )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ ERR err = JET_errSuccess;
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrRandomInsert() );
+
+ int nodes = tf.m_bbtBuff.CNodes();
+ KEY keyPrev;
+ keyPrev.Nullify();
+
+ // Scan all nodes including duplicates.
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveFirst( BBTBuff::sfAllowDuplicates ) );
+ for ( int i = 0; i < nodes; i++ )
+ {
+ SkipListNode* pnode = tf.m_bbtBuff.PnodeCurr();
+ CHECK( pnode->CmpKey( keyPrev ) >= 0 );
+ keyPrev = pnode->Key();
+ err = tf.m_bbtBuff.ErrMoveNext( BBTBuff::sfAllowDuplicates );
+ }
+
+ wprintf( L"Scanned %d nodes. ", nodes );
+ CHECK( err == errBBTNodeNotFound );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, ScanForwardUnique )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ ERR err = JET_errSuccess;
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16 ) );
+
+ int iData = 0;
+ KEY keyPrev;
+ DATA data;
+ keyPrev.Nullify();
+ data.Nullify();
+ data.SetPv( &iData );
+ data.SetCb( sizeof( iData ) );
+
+ // Scan unique nodes (latest versions).
+ int nodes = 0;
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveFirst( BBTBuff::sfSkipDuplicates ) );
+ do
+ {
+ SkipListNode* pnode = tf.m_bbtBuff.PnodeCurr();
+ CHECK( pnode->CmpKey( keyPrev ) > 0 );
+ CHECK( CmpData( data, pnode->Data() ) < 0 );
+ keyPrev = pnode->Key();
+ nodes++;
+ }
+ while( JET_errSuccess == ( err = tf.m_bbtBuff.ErrMoveNext( BBTBuff::sfSkipDuplicates ) ) );
+
+ wprintf( L"Scanned %d unique nodes. ", nodes );
+ CHECK( err == errBBTNodeNotFound );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, ScanReverse )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ ERR err = JET_errSuccess;
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrRandomInsert() );
+
+ int nodes = tf.m_bbtBuff.CNodes();
+ KEY keyPrev;
+ keyPrev.Nullify();
+
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveLast() );
+ for ( int i = 0; i < nodes; i++ )
+ {
+ SkipListNode* pnode = tf.m_bbtBuff.PnodeCurr();
+ CHECK( pnode->CmpKey( keyPrev ) <= 0 || keyPrev.FNull() );
+ keyPrev = pnode->Key();
+ err = tf.m_bbtBuff.ErrMovePrev( BBTBuff::sfAllowDuplicates );
+ }
+
+ wprintf( L"Scanned %d nodes. ", nodes );
+ CHECK( err == errBBTNodeNotFound );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, ScanReverseUnique )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ ERR err = JET_errSuccess;
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16 ) );
+
+ int iData = 0;
+ KEY keyPrev;
+ DATA data;
+ keyPrev.Nullify();
+ data.Nullify();
+ data.SetPv( &iData );
+ data.SetCb( sizeof( iData ) );
+
+ // Scan unique nodes (latest versions).
+ int nodes = 0;
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveLast() );
+ do
+ {
+ SkipListNode* pnode = tf.m_bbtBuff.PnodeCurr();
+ CHECK( pnode->CmpKey( keyPrev ) < 0 || keyPrev.FNull() );
+ CHECK( CmpData( data, pnode->Data() ) < 0 );
+ keyPrev = pnode->Key();
+ nodes++;
+ } while ( JET_errSuccess == ( err = tf.m_bbtBuff.ErrMovePrev( BBTBuff::sfSkipDuplicates ) ) );
+
+ wprintf( L"Scanned %d unique nodes. ", nodes );
+ CHECK( err == errBBTNodeNotFound );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, SeekModes )
+// ================================================================
+{
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16 ) );
+
+ BigEndian be_key;
+ int iData = 0;
+ KEY key;
+ DATA data;
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+ data.SetPv( &iData );
+ data.SetCb( sizeof( iData ) );
+
+ SkipListLink rgLinks[ MAX_LEVELS ];
+ SkipListNode* rgpNodes[ MAX_LEVELS ];
+
+ auto testSeek = [&]( int iKey, BBTBuff::SeekMode seekMode, BBTBuff::SeekPos seekPos, int iExpectedResult, bool fNodeFound )
+ {
+ int iSeekResult;
+ memset( rgLinks, 0, sizeof( rgLinks ) );
+ memset( rgpNodes, 0, sizeof( rgpNodes ) );
+ be_key = iKey;
+
+ CHECK_CALL( tf.m_bbtBuff.ErrSeek_( key, seekMode, seekPos, &iSeekResult, rgLinks, rgpNodes ) );
+ CHECK( iSeekResult * iExpectedResult > 0 || iSeekResult == iExpectedResult ); // both have the same sign, or they are 0
+
+ SkipListNode* pnodeSeeked = rgpNodes[ 0 ];
+ CHECK( !!pnodeSeeked == fNodeFound );
+
+ if ( pnodeSeeked == NULL )
+ {
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveFirst( BBTBuff::sfAllowDuplicates ) );
+ pnodeSeeked = tf.m_bbtBuff.PnodeCurr();
+ }
+ else if ( seekPos == BBTBuff::SeekPos::Prev )
+ {
+ // Returned node is prev to the node where the seek landed.
+ CHECK( pnodeSeeked->FDuplicateNext0() ); // each key in the test has duplicates, so prev node should always be a duplicate
+ CHECK_CALL( tf.m_bbtBuff.ErrSetCurrNodeFromLink( pnodeSeeked->LinkNext0() ) );
+ pnodeSeeked = tf.m_bbtBuff.PnodeCurr();
+ }
+
+ int cmpActual = CmpKey( pnodeSeeked->Key(), key );
+ CHECK( ( cmpActual * iExpectedResult ) > 0 || cmpActual == iExpectedResult ); // both have the same sign, or they are 0
+
+ (void)tf.m_bbtBuff.ErrSetCurrNodeFromLink( rgLinks[ 0 ] );
+ CHECK( tf.m_bbtBuff.PnodeCurr() == rgpNodes[ 0 ] );
+
+ int i = 0;
+ if ( fNodeFound )
+ {
+ int level = pnodeSeeked->Level();
+ if ( seekPos == BBTBuff::SeekPos::Prev )
+ {
+ SkipListLink linkSeeked = rgpNodes[ 0 ]->LinkNext0();
+ for ( i = 0; i <= level; i++ )
+ {
+ // For SeekPos::Prev, returned nodes should be strictly the prev node to seeked node
+ // at current level.
+ CHECK( linkSeeked == rgpNodes[ i ]->RgLinksNext()[ i ] );
+ (void) tf.m_bbtBuff.ErrSetCurrNodeFromLink( rgLinks[ i ] );
+ CHECK( tf.m_bbtBuff.PnodeCurr() == rgpNodes[ i ] );
+ }
+ }
+ else
+ {
+ for ( i = 1; i <= level; i++ )
+ {
+ CHECK( pnodeSeeked == rgpNodes[ i ] );
+ CHECK( rgLinks[ i - 1 ] == rgLinks[ i ] );
+ }
+
+ CHECK( rgpNodes[ i ] != rgpNodes[ i - 1 ] ); // can't be the same node, levels are different
+ }
+
+ for ( i; i < MAX_LEVELS; i++ )
+ {
+ if ( rgpNodes[ i ] != NULL )
+ {
+ // This node must be a prev/same node to lower level node
+ if ( rgpNodes[ i ] != rgpNodes[ i - 1 ] )
+ {
+ int cmp = CmpKey( rgpNodes[ i ]->Key(), rgpNodes[ i - 1 ]->Key() );
+ CHECK( cmp < 0 || ( cmp == 0 &&
+ ( (int*) rgpNodes[ i ]->Data().Pv() ) <= ( (int*) rgpNodes[ i - 1 ]->Data().Pv() ) ) );
+ }
+
+ (void) tf.m_bbtBuff.ErrSetCurrNodeFromLink( rgLinks[ i ] );
+ CHECK( tf.m_bbtBuff.PnodeCurr() == rgpNodes[ i ] );
+
+ (void) tf.m_bbtBuff.ErrSetCurrNodeFromLink( rgLinks[ i - 1 ] );
+ CHECK( tf.m_bbtBuff.PnodeCurr() == rgpNodes[ i - 1 ] );
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ for ( i; i < MAX_LEVELS; i++ )
+ {
+ CHECK( rgpNodes[ i ] == NULL );
+ CHECK( rgLinks[ i ] == NULL );
+ }
+ };
+
+ // Seek before first key.
+ testSeek( 50, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Curr, 1, false );
+ testSeek( 50, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Curr, 1, false );
+ testSeek( 50, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Prev, 1, false );
+ testSeek( 50, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Prev, 1, false );
+
+ // Seek to first key.
+ testSeek( 100, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Curr, 0, false );
+ testSeek( 100, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Curr, 0, true );
+ testSeek( 100, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Prev, 0, false );
+ testSeek( 100, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Prev, 0, true ); // will land on older duplicate version of first key
+
+ // Seek before some key in the middle.
+ testSeek( 950, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Curr, -1, true );
+ testSeek( 950, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Curr, -1, true );
+ testSeek( 950, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Prev, -1, true );
+ testSeek( 950, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Prev, -1, true );
+
+ // Seek to some key in the middle.
+ testSeek( 1100, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Curr, -1, true );
+ testSeek( 1100, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Curr, 0, true );
+ testSeek( 1100, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Prev, -1, true );
+ testSeek( 1100, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Prev, 0, true );
+
+ // Seek after last.
+ testSeek( 1800, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Curr, -1, true );
+ testSeek( 1800, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Curr, -1, true );
+ testSeek( 1800, BBTBuff::SeekMode::LT, BBTBuff::SeekPos::Curr, -1, true );
+ testSeek( 1800, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Curr, -1, true );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, SeekLEQ )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16 ) );
+
+ BigEndian be_key;
+ int iData = 0;
+ KEY key;
+ DATA data;
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+ data.SetPv( &iData );
+ data.SetCb( sizeof( iData ) );
+
+ // Seek equal.
+ be_key = 600;
+ CHECK( JET_errSuccess == tf.m_bbtBuff.ErrSeekLEQ( key ) );
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+ CHECK( CmpData( data, tf.m_bbtBuff.PnodeCurr()->Data() ) < 0 ); // must seek to latest version
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveNext( BBTBuff::sfAllowDuplicates ) );
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) > 0 ); // latest node in the sequence means next node can't have the same key
+
+ // Seek LT.
+ be_key = 599;
+ CHECK( wrnNDFoundLess == tf.m_bbtBuff.ErrSeekLEQ( key ) );
+ be_key = 500;
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+ CHECK( CmpData( data, tf.m_bbtBuff.PnodeCurr()->Data() ) < 0 );
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveNext( BBTBuff::sfAllowDuplicates ) );
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) > 0 );
+
+ // Seek to lowest key.
+ be_key = 0;
+ CHECK( wrnNDFoundGreater == tf.m_bbtBuff.ErrSeekLEQ( key ) );
+ be_key = 100;
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+ CHECK( CmpData( data, tf.m_bbtBuff.PnodeCurr()->Data() ) < 0 );
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveNext( BBTBuff::sfAllowDuplicates ) );
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) > 0 );
+
+ // Seek to highest key.
+ be_key = INT_MAX;
+ CHECK( wrnNDFoundLess == tf.m_bbtBuff.ErrSeekLEQ( key ) );
+ be_key = 1700;
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+ CHECK( CmpData( data, tf.m_bbtBuff.PnodeCurr()->Data() ) < 0 );
+ CHECK( errBBTNodeNotFound == tf.m_bbtBuff.ErrMoveNext( BBTBuff::sfAllowDuplicates ) );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, SeekGEQOldest )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16 ) );
+
+ BigEndian be_key;
+ int iData = 0;
+ KEY key;
+ DATA data;
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+ data.SetPv( &iData );
+ data.SetCb( sizeof( iData ) );
+
+ // Seek equal.
+ be_key = 700;
+ CHECK( JET_errSuccess == tf.m_bbtBuff.ErrSeekGEQOldest( key ) );
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+ CHECK( CmpData( data, tf.m_bbtBuff.PnodeCurr()->Data() ) == 0 ); // must seek to oldest version
+ CHECK_CALL( tf.m_bbtBuff.ErrMovePrev( BBTBuff::sfAllowDuplicates ) );
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) < 0 ); // oldest node in the sequence means prev node can't have the same key
+
+ // Seek GT.
+ be_key = 599;
+ CHECK( wrnNDFoundGreater == tf.m_bbtBuff.ErrSeekGEQOldest( key ) );
+ be_key = 600;
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+ CHECK( CmpData( data, tf.m_bbtBuff.PnodeCurr()->Data() ) == 0 );
+ CHECK_CALL( tf.m_bbtBuff.ErrMovePrev( BBTBuff::sfAllowDuplicates ) );
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) < 0 );
+
+ // Seek to lowest key.
+ be_key = 0;
+ CHECK( wrnNDFoundGreater == tf.m_bbtBuff.ErrSeekGEQOldest( key ) );
+ be_key = 100;
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+ CHECK( CmpData( data, tf.m_bbtBuff.PnodeCurr()->Data() ) == 0 );
+ CHECK( errBBTNodeNotFound == tf.m_bbtBuff.ErrMovePrev( BBTBuff::sfAllowDuplicates ) );
+
+ // Seek to highest key.
+ // Expected: this will return node not found. Will not seek to a smaller key
+ // (unlike ErrSeekLEQ() which seeks to a GT key if no LEQ keys are found).
+ be_key = INT_MAX;
+ CHECK( errBBTNodeNotFound == tf.m_bbtBuff.ErrSeekGEQOldest( key ) );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, Delete )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16 ) );
+
+ ERR err;
+ BigEndian be_key;
+ int iData = 0;
+ int cNodesBegin = tf.m_pbbtHeader->le_cNodes;
+ int cNodesDel = 0;
+ KEY key;
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+
+ // Get latest version's data.
+ be_key = 1400;
+ CHECK_CALL( tf.m_bbtBuff.ErrSeekLEQ( key ) );
+ iData = *( (int*) tf.m_bbtBuff.PnodeCurr()->Data().Pv() );
+ CHECK( iData != 0 );
+
+ // Delete all versions of a node (latest to oldest).
+ for ( int i = iData; i > 0; i-- )
+ {
+ CHECK_CALL( tf.m_bbtBuffWriter.ErrDelete( key ) );
+ CHECK_CALL( tf.m_bbtBuff.ErrSeekLEQ( key ) );
+ int iDataCurr = *( (int*) tf.m_bbtBuff.PnodeCurr()->Data().Pv() );
+ CHECK( iDataCurr == i - 1 );
+ cNodesDel++;
+ }
+
+ // Last version.
+ CHECK_CALL( tf.m_bbtBuffWriter.ErrDelete( key ) );
+ CHECK( wrnNDFoundLess == tf.m_bbtBuff.ErrSeekLEQ( key ) );
+ cNodesDel++;
+
+ // Delete all versions of first node.
+ be_key = 100;
+ while ( JET_errSuccess == ( err = tf.m_bbtBuffWriter.ErrDelete( key ) ) )
+ {
+ cNodesDel++;
+ }
+
+ CHECK( err == errBBTNodeNotFound );
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveFirst( BBTBuff::sfSkipDuplicates ) );
+ be_key = 200;
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+
+ // Delete all versions of last node.
+ be_key = 1700;
+ while ( JET_errSuccess == ( err = tf.m_bbtBuffWriter.ErrDelete( key ) ) )
+ {
+ cNodesDel++;
+ }
+
+ CHECK( err == errBBTNodeNotFound );
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveLast() );
+ be_key = 1600;
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+
+ wprintf( L"%d nodes deleted. ", cNodesDel );
+ CHECK( tf.m_pbbtHeader->le_cNodes == cNodesBegin - cNodesDel );
+ CHECK_CALL( tf.m_bbtBuff.ErrValidate() );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, RangeDelete )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16 ) );
+
+ BigEndian be_key;
+ KEY key;
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+
+ // Get latest version's data.
+ be_key = 1400;
+ CHECK_CALL( tf.m_bbtBuff.ErrSeekGEQOldest( key ) );
+ SkipListLink linkStart = tf.m_bbtBuff.GetLinkToCurrNode();
+ int cNodesToDel = 1;
+ while ( tf.m_bbtBuff.PnodeCurr()->FDuplicateNext0() )
+ {
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveNext( BBTBuff::sfAllowDuplicates ) );
+ cNodesToDel++;
+ }
+
+ int cNodes = tf.m_pbbtHeader->le_cNodes;
+ CHECK_CALL( tf.m_bbtBuffWriter.ErrRangeDelete( linkStart, cNodesToDel ) );
+ CHECK( cNodes - cNodesToDel == tf.m_pbbtHeader->le_cNodes );
+
+ CHECK( wrnNDFoundLess == tf.m_bbtBuff.ErrSeekLEQ( key ) );
+ be_key = 1300;
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+ be_key = 1500;
+ tf.m_bbtBuff.ErrMoveNext( BBTBuff::sfAllowDuplicates );
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+
+ // RangeDelete from 1500 to end.
+ linkStart = tf.m_bbtBuff.GetLinkToCurrNode();
+ cNodesToDel = 1;
+ while ( JET_errSuccess == tf.m_bbtBuff.ErrMoveNext( BBTBuff::sfAllowDuplicates ) )
+ {
+ cNodesToDel++;
+ }
+
+ cNodes = tf.m_pbbtHeader->le_cNodes;
+ CHECK_CALL( tf.m_bbtBuffWriter.ErrRangeDelete( linkStart, cNodesToDel ) );
+ CHECK( cNodes - cNodesToDel == tf.m_pbbtHeader->le_cNodes );
+
+ be_key = 1300;
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveLast() );
+ CHECK( tf.m_bbtBuff.PnodeCurr()->CmpKey( key ) == 0 );
+ wprintf( L"%d nodes deleted. ", cNodesToDel );
+
+ CHECK_CALL( tf.m_bbtBuff.ErrValidate() );
+}
+
+// ================================================================
+JETUNITTESTEX( BBTBuff, Reogranize, JetSimpleUnitTest::dwBufferManager )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16 ) );
+
+ BigEndian be_key;
+ KEY key;
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+
+ // Delete all versions of a node (latest to oldest).
+ int cNodesDel = tf.m_pbbtHeader->le_cNodes;
+ CHECK_CALL( tf.ErrDeleteKey( 1400 ) );
+ cNodesDel -= tf.m_pbbtHeader->le_cNodes;
+ CHECK( cNodesDel > 0 );
+
+ int ibMicFree = tf.m_pbbtHeader->le_ibMicFree->ToInt();
+ CHECK_CALL( tf.m_bbtBuffWriter.ErrReorganize() );
+
+ int ibMicFreeNew = tf.m_pbbtHeader->le_ibMicFree->ToInt();
+ constexpr int cbSmallestNode = SkipListNode::Cb( 0, sizeof( int ), sizeof( int ) );
+
+ // Reorganize() should atleast free up this much space, assuming every node was level0 (least overhead).
+ CHECK( ibMicFreeNew + cNodesDel * cbSmallestNode <= ibMicFree );
+ wprintf( L"Freed up %d bytes. ", ibMicFree - ibMicFreeNew );
+
+ CHECK_CALL( tf.m_bbtBuff.ErrValidate() );
+}
+
+
+class MergeAndDelTestFixture : public JetTestFixture
+{
+public:
+ BBTBuffTestFixture tf;
+ BBTBuffTestFixture tfFrom;
+ FixedHeapArray rgLinksToDel;
+ FixedHeapArray rgpNodesToMerge;
+ int cLinksToDel = 0;
+ int cNodesToMerge = 0;
+
+ MergeAndDelTestFixture( JetUnitTestResult* presult ) : JetTestFixture( presult )
+ {}
+
+ void Prepare()
+ {
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16 ) );
+ CHECK( errBBTBuffFull == tfFrom.ErrHotpointInsert( 100, 20 ) );
+
+ BigEndian be_key;
+ KEY key;
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+
+ // Make some room by marking some nodes for deletion.
+ be_key = 1400;
+ CHECK_CALL( tf.m_bbtBuff.ErrSeekLEQ( key ) );
+ int cNodesPerKey = 1 + *( (int*) tf.m_bbtBuff.PnodeCurr()->Data().Pv() );
+
+ rgLinksToDel = FixedHeapArray::MakeArray( cNodesPerKey * 3 );
+ auto addLinkToDel = [this]( SkipListNode* pnode )
+ {
+ rgLinksToDel[ cLinksToDel++ ] = tf.m_bbtBuff.GetLinkToCurrNode();
+ };
+
+ CHECK_CALL( tf.ErrKeyForEachOldestToLatest( 1000, addLinkToDel ) );
+ cLinksToDel--; // deliberately leave 1 node from this key behind
+ CHECK_CALL( tf.ErrKeyForEachOldestToLatest( 1300, addLinkToDel ) );
+ cLinksToDel--;
+ CHECK_CALL( tf.ErrKeyForEachOldestToLatest( 1500, addLinkToDel ) );
+ cLinksToDel--;
+
+ CHECK( cLinksToDel <= cNodesPerKey * 3 );
+
+ // Get nodes to merge.
+ rgpNodesToMerge = FixedHeapArray::MakeArray( cNodesPerKey * 5 );
+ auto addNodesToMerge = [this]( SkipListNode* pnode )
+ {
+ rgpNodesToMerge[ cNodesToMerge++ ] = pnode;
+ };
+
+ // Gather more nodes than the amount that can fit.
+ CHECK_CALL( tfFrom.ErrKeyForEachOldestToLatest( 100, addNodesToMerge ) );
+ CHECK_CALL( tfFrom.ErrKeyForEachOldestToLatest( 500, addNodesToMerge ) );
+ CHECK_CALL( tfFrom.ErrKeyForEachOldestToLatest( 1000, addNodesToMerge ) );
+ CHECK_CALL( tfFrom.ErrKeyForEachOldestToLatest( 1500, addNodesToMerge ) );
+ CHECK_CALL( tfFrom.ErrKeyForEachOldestToLatest( 1900, addNodesToMerge ) );
+ }
+
+ // This class derives from JetTestFixture just to make CHECK() macros work.
+ // Setup_()/Teardown_() isn't used.
+protected:
+ bool SetUp_() { return false; }
+ void TearDown_() {}
+};
+
+// ================================================================
+JETUNITTESTEX( BBTBuff, MergeAndDel, JetSimpleUnitTest::dwBufferManager )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ MergeAndDelTestFixture md( m_presult );
+ md.Prepare();
+
+ int cNodesBefore = md.tf.m_pbbtHeader->le_cNodes;
+ int cNodesMerged = 0;
+ int cNodesDeleted = 0;
+ ERR err = md.tf.m_bbtBuffWriter.ErrMergeAndDelNodes(
+ md.rgpNodesToMerge.PrgT(),
+ md.rgLinksToDel.PrgT(),
+ md.cNodesToMerge,
+ md.cLinksToDel,
+ &cNodesMerged,
+ &cNodesDeleted,
+ 0 );
+
+ wprintf( L"%d nodes merged, %d deleted. ", cNodesMerged, cNodesDeleted );
+ CHECK( err == wrnBBTMergeTargetFull );
+ CHECK( cNodesMerged <= md.cNodesToMerge );
+ CHECK( cNodesDeleted == md.cLinksToDel );
+ CHECK( cNodesBefore + cNodesMerged - cNodesDeleted == md.tf.m_pbbtHeader->le_cNodes );
+ CHECK_CALL( md.tf.m_bbtBuff.ErrValidate() );
+}
+
+// ================================================================
+JETUNITTESTEX( BBTBuff, MergeAndDelNoSpace, JetSimpleUnitTest::dwBufferManager )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ BBTBuffTestFixture tfFrom;
+ CHECK( errBBTBuffFull == tf.ErrHotpointInsert( 100, 16, 0 ) ); // takes a long time because of n^2 runtime.
+ CHECK( errBBTBuffFull == tfFrom.ErrHotpointInsert( 100, 20 ) );
+
+ BigEndian be_key;
+ KEY key;
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+
+ // Make some room by marking some nodes for deletion.
+ int cLinksToDel = 10;
+ unique_ptr rgLinksToDel( new SkipListLink[ cLinksToDel ] );
+
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveFirst( BBTBuff::sfSkipDuplicates ) );
+ for ( int i = 0; i < cLinksToDel; i++ )
+ {
+ rgLinksToDel[ i ] = tf.m_bbtBuff.GetLinkToCurrNode();
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveNext( BBTBuff::sfSkipDuplicates ) );
+ }
+
+ // Get nodes to merge.
+ int cNodesToMerge = 10;
+ unique_ptr rgpNodesToMerge( new const SkipListNode * [ cNodesToMerge ] );
+ CHECK_CALL( tfFrom.m_bbtBuff.ErrMoveFirst( BBTBuff::sfSkipDuplicates ) );
+ for ( int i = 0; i < cNodesToMerge; i++ )
+ {
+ rgLinksToDel[ i ] = tfFrom.m_bbtBuff.GetLinkToCurrNode();
+ CHECK_CALL( tfFrom.m_bbtBuff.ErrMoveNext( BBTBuff::sfSkipDuplicates ) );
+ }
+
+ int cNodesBefore = tf.m_pbbtHeader->le_cNodes;
+ int cNodesMerged = 0;
+ int cNodesDeleted = 0;
+ ERR err = tf.m_bbtBuffWriter.ErrMergeAndDelNodes(
+ rgpNodesToMerge.get(),
+ rgLinksToDel.get(),
+ cNodesToMerge,
+ cLinksToDel,
+ &cNodesMerged,
+ &cNodesDeleted,
+ 0 );
+
+ CHECK( err == errBBTBuffFull );
+ CHECK( cNodesMerged == 0 );
+ CHECK( cNodesDeleted == 0 );
+ CHECK( cNodesBefore + cNodesMerged - cNodesDeleted == tf.m_pbbtHeader->le_cNodes );
+ CHECK_CALL( tf.m_bbtBuff.ErrValidate() );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, Dump )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ CHECK( JET_errSuccess == tf.ErrRandomInsert( 10 ) );
+
+ std::string szDump = DumpBBTBuff( tf.m_bbtBuff, 0 );
+ wprintf( L"\n%hs\n", szDump.c_str() );
+}
+
+
+////////////////////////////////////////////////////////////////////
+// Negative tests. Tests with failed dml because of failed trx log.
+
+// ================================================================
+JETUNITTEST( BBTBuff, FailedInsert )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ BigEndian be_key = 42;
+ int iData = 10;
+ KEY key;
+ DATA data;
+
+ key.Nullify();
+ key.suffix.SetPv( &be_key );
+ key.suffix.SetCb( sizeof( be_key ) );
+ data.Nullify();
+ data.SetPv( &iData );
+ data.SetCb( sizeof( iData ) );
+
+ CHECK_CALL( tf.ErrRandomInsert( 10 ) );
+
+ DBTIME dbtimeInitial = tf.m_rgcsr[ 0 ].Dbtime();
+ tf.m_bbtBuffTrxLogger.m_returnErr = ErrERRCheck( JET_errLogWriteFail );
+ tf.m_bbtBuffTrxLogger.m_dbtimeCoordinated = dbtimeInitial + 10;
+ CHECK( JET_errLogWriteFail == tf.m_bbtBuffWriter.ErrInsert( bbtOpInsert, key, data, fSLNNone ) );
+
+ CHECK_CALL( tf.m_bbtBuff.ErrValidate() );
+ CHECK( 10 == tf.m_pbbtHeader->le_cNodes );
+ tf.m_rgcsr.ForEach( [this, dbtimeInitial]( const CSR& csr )
+ {
+ CHECK( csr.Dbtime() == dbtimeInitial );
+ } );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, FailedDelete )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+ KEY key;
+ DATA data;
+
+ CHECK_CALL( tf.ErrRandomInsert( 10 ) );
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveFirst( BBTBuff::sfSkipDuplicates ) );
+
+ key = tf.m_bbtBuff.PnodeCurr()->Key();
+ data = tf.m_bbtBuff.PnodeCurr()->Data();
+
+ DBTIME dbtimeInitial = tf.m_rgcsr[ 0 ].Dbtime();
+ tf.m_bbtBuffTrxLogger.m_returnErr = ErrERRCheck( JET_errLogWriteFail );
+ tf.m_bbtBuffTrxLogger.m_dbtimeCoordinated = dbtimeInitial + 10;
+ CHECK( JET_errLogWriteFail == tf.m_bbtBuffWriter.ErrDelete( key ) );
+
+ CHECK_CALL( tf.m_bbtBuff.ErrValidate() );
+ CHECK( 10 == tf.m_pbbtHeader->le_cNodes );
+ tf.m_rgcsr.ForEach( [this, dbtimeInitial]( const CSR& csr )
+ {
+ CHECK( csr.Dbtime() == dbtimeInitial );
+ } );
+}
+
+// ================================================================
+JETUNITTEST( BBTBuff, FailedRangeDelete )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ BBTBuffTestFixture tf;
+
+ CHECK_CALL( tf.ErrRandomInsert( 10 ) );
+ CHECK_CALL( tf.m_bbtBuff.ErrMoveFirst( BBTBuff::sfSkipDuplicates ) );
+
+ SkipListLink linkFirst = tf.m_bbtBuff.GetLinkToCurrNode();
+ DBTIME dbtimeInitial = tf.m_rgcsr[ 0 ].Dbtime();
+ tf.m_bbtBuffTrxLogger.m_returnErr = ErrERRCheck( JET_errLogWriteFail );
+ tf.m_bbtBuffTrxLogger.m_dbtimeCoordinated = dbtimeInitial + 10;
+ CHECK( JET_errLogWriteFail == tf.m_bbtBuffWriter.ErrRangeDelete( linkFirst, 5 ) );
+
+ CHECK_CALL( tf.m_bbtBuff.ErrValidate() );
+ CHECK( 10 == tf.m_pbbtHeader->le_cNodes );
+ tf.m_rgcsr.ForEach( [this, dbtimeInitial]( const CSR& csr )
+ {
+ CHECK( csr.Dbtime() == dbtimeInitial );
+ } );
+}
+
+// ================================================================
+JETUNITTESTEX( BBTBuff, FailedMergeAndDel, JetSimpleUnitTest::dwBufferManager )
+// ================================================================
+{
+ SetParam( pinstNil, ppibNil, JET_paramDatabasePageSize, 32768, NULL );
+
+ MergeAndDelTestFixture md( m_presult );
+ md.Prepare();
+
+ DBTIME dbtimeInitial = md.tf.m_rgcsr[ 0 ].Dbtime();
+ md.tf.m_bbtBuffTrxLogger.m_dbtimeCoordinated = dbtimeInitial + 10;
+ md.tf.m_bbtBuffTrxLogger.m_returnErr = ErrERRCheck( JET_errLogWriteFail );
+
+ int cNodesBefore = md.tf.m_pbbtHeader->le_cNodes;
+ int cNodesMerged = 0;
+ int cNodesDeleted = 0;
+ ERR err = md.tf.m_bbtBuffWriter.ErrMergeAndDelNodes(
+ md.rgpNodesToMerge.PrgT(),
+ md.rgLinksToDel.PrgT(),
+ md.cNodesToMerge,
+ md.cLinksToDel,
+ &cNodesMerged,
+ &cNodesDeleted,
+ 0 );
+
+ wprintf( L"%d nodes merged, %d deleted. ", cNodesMerged, cNodesDeleted );
+ CHECK( err == JET_errLogWriteFail );
+ CHECK( cNodesMerged == 0 );
+ CHECK( cNodesDeleted == 0 );
+ CHECK( cNodesBefore == md.tf.m_pbbtHeader->le_cNodes );
+ CHECK_CALL( md.tf.m_bbtBuff.ErrValidate() );
+ md.tf.m_rgcsr.ForEach( [this, dbtimeInitial]( const CSR& csr )
+ {
+ CHECK( csr.Dbtime() == dbtimeInitial );
+ } );
+}
+
diff --git a/dev/ese/src/ese/bf.cxx b/dev/ese/src/ese/bf.cxx
index 0d585889..4a1f8dcd 100644
--- a/dev/ese/src/ese/bf.cxx
+++ b/dev/ese/src/ese/bf.cxx
@@ -6,7 +6,6 @@
-
// Only Init requires the global cbPage, subsequent this point the buffer manager is page independent, and
// supports multiple page sizes concurrently.
//
@@ -4648,6 +4647,10 @@ ERR ErrBFFlush( IFMP ifmp, const OBJID objidFDP, const PGNO pgnoFirst, const PGN
}
while ( fRetryFlush );
+ if ( g_rgfmp[ ifmp ].FRBSOn() && ( g_rgfmp[ ifmp ].PRBS()->ErrFlushAll() >= JET_errSuccess ) )
+ {
+ g_rgfmp[ ifmp ].PRBS()->AssertAllFlushed();
+ }
const ERR errBfFlushLoop = err;
OSTraceFMP(
@@ -5252,7 +5255,7 @@ void BFIBuildReferencedPageListForCrashDump( CReferencedPages * ptableReferenced
// means that the page won't be included
// in our list of referenced pages)
- (void) arrayReferencedPages.ErrSetEntry( arrayReferencedPages.Size(), pagepointer );
+ (void) arrayReferencedPages.ErrAppendEntry( pagepointer );
}
}
}
@@ -6274,6 +6277,43 @@ void BFIFTLTerm()
#define ENABLE_BFFTL_TRACING
#endif
+ULONG g_ulSamplingRatio = 0;
+// Mask of all keywords that have events in common with BFRESMGRSUBSAMPLED.
+const ULONGLONG g_ullSamplingKeywordMask = _etguidKeywordPerformance | _etguidKeywordBF | _etguidKeywordBFRESMGR | _etguidKeywordDataWorkingSet;
+
+void BFICacheTraceSamplingInit( const ULONG ulSamplingRatio )
+{
+ g_ulSamplingRatio = ulSamplingRatio;
+}
+
+// Do not emit the events for ResMgrInit and ResMgrTerm if g_ulSamplingRatio is equals to 0
+// and no other keyword with events in common with BFRESMGRSUBSAMPLED are set.
+INLINE bool FBFIDoNotEmitBfResMgrInitTermTrace()
+{
+ return ( ( g_ulSamplingRatio == 0 ) &&
+ !FOSEventTraceAnyKeywordEnabled( g_ullSamplingKeywordMask ) );
+}
+
+// Subsample the cache trace by preventing some events from being emitted.
+// Subsampling is only possible if no other keyword with events in common with BFRESMGRSUBSAMPLED are set and BFRESMGRSUBSAMPLED is set.
+// If g_ulSamplingRatio is set to 0, no events are emitted.
+// With g_ulSamplingRatio > 0, only the events for 1 in g_ulSamplingRatio pages are traced on average.
+INLINE bool FBFIDoNotEmitBfResMgrPageTrace( const IFMP ifmp, const PGNO pgno )
+{
+ if ( ( g_ulSamplingRatio == 1 ) || FOSEventTraceAnyKeywordEnabled( g_ullSamplingKeywordMask ) )
+ {
+ return fFalse;
+ }
+
+ if ( ( g_ulSamplingRatio == 0 ) || !FOSEventTraceKeywordEnabled<_etguidKeywordBFRESMGRSUBSAMPLED>() )
+ {
+ return fTrue;
+ }
+
+ return ( ( ( IFMPPGNO( ifmp, pgno ).Hash() ) % g_ulSamplingRatio ) != 0 );
+}
+
+
INLINE void BFITraceResMgrInit(
const INT K,
const double csecCorrelatedTouch,
@@ -6283,35 +6323,41 @@ INLINE void BFITraceResMgrInit(
const double dblHashUniformity,
const double dblSpeedSizeTradeoff )
{
+ if ( !FBFIDoNotEmitBfResMgrInitTermTrace() )
+ {
#ifdef ENABLE_BFFTL_TRACING
- (void)ErrBFIFTLSysResMgrInit(
- K,
- csecCorrelatedTouch,
- csecTimeout,
- csecUncertainty,
- dblHashLoadFactor,
- dblHashUniformity,
- dblSpeedSizeTradeoff );
+ ( void )ErrBFIFTLSysResMgrInit(
+ K,
+ csecCorrelatedTouch,
+ csecTimeout,
+ csecUncertainty,
+ dblHashLoadFactor,
+ dblHashUniformity,
+ dblSpeedSizeTradeoff );
#endif // ENABLE_BFFTL_TRACING
- ETResMgrInit(
- TickOSTimeCurrent(),
- K,
- csecCorrelatedTouch,
- csecTimeout,
- csecUncertainty,
- dblHashLoadFactor,
- dblHashUniformity,
- dblSpeedSizeTradeoff );
+ ETResMgrInit(
+ TickOSTimeCurrent(),
+ K,
+ csecCorrelatedTouch,
+ csecTimeout,
+ csecUncertainty,
+ dblHashLoadFactor,
+ dblHashUniformity,
+ dblSpeedSizeTradeoff );
+ }
}
INLINE void BFITraceResMgrTerm()
{
+ if ( !FBFIDoNotEmitBfResMgrInitTermTrace() )
+ {
#ifdef ENABLE_BFFTL_TRACING
- (void)ErrBFIFTLSysResMgrTerm();
+ ( void )ErrBFIFTLSysResMgrTerm();
#endif // ENABLE_BFFTL_TRACING
- ETResMgrTerm( TickOSTimeCurrent() );
+ ETResMgrTerm( TickOSTimeCurrent() );
+ }
}
INLINE void BFITraceCachePage(
@@ -6323,21 +6369,24 @@ INLINE void BFITraceCachePage(
const BFRequestTraceFlags bfrtf,
const TraceContext& tc )
{
- GetCurrUserTraceContext getutc;
- const BYTE bClientType = getutc->context.nClientType;
+ if ( !FBFIDoNotEmitBfResMgrPageTrace( pbf->ifmp, pbf->pgno ) )
+ {
+ GetCurrUserTraceContext getutc;
+ const BYTE bClientType = getutc->context.nClientType;
#ifdef ENABLE_BFFTL_TRACING
#endif // ENABLE_BFFTL_TRACING
- ETCacheCachePage(
- tickCache,
- pbf->ifmp,
- pbf->pgno,
- bflf,
- bflt,
- pctPriority,
- bfrtf,
- bClientType );
+ ETCacheCachePage(
+ tickCache,
+ pbf->ifmp,
+ pbf->pgno,
+ bflf,
+ bflt,
+ pctPriority,
+ bfrtf,
+ bClientType );
+ }
}
INLINE void BFITraceRequestPage(
@@ -6349,43 +6398,47 @@ INLINE void BFITraceRequestPage(
const BFRequestTraceFlags bfrtf,
const TraceContext& tc )
{
+ if ( !FBFIDoNotEmitBfResMgrPageTrace( pbf->ifmp, pbf->pgno ) )
+ {
#ifdef ENABLE_BFFTL_TRACING
- GetCurrUserTraceContext getutc;
- const BYTE bClientType = getutc->context.nClientType;
+ GetCurrUserTraceContext getutc;
+ const BYTE bClientType = getutc->context.nClientType;
- (void)ErrBFIFTLTouch(
- tickTouch,
- pbf->ifmp,
- pbf->pgno,
- bflt,
- bClientType,
- pctPriority,
- !!( bfrtf & bfrtfUseHistory ),
- !!( bfrtf & bfrtfNewPage ),
- !!( bfrtf & bfrtfNoTouch ),
- !!( bfrtf & bfrtfDBScan ) );
+ (void) ErrBFIFTLTouch(
+ tickTouch,
+ pbf->ifmp,
+ pbf->pgno,
+ bflt,
+ bClientType,
+ pctPriority,
+ !!( bfrtf & bfrtfUseHistory ),
+ !!( bfrtf & bfrtfNewPage ),
+ !!( bfrtf & bfrtfNoTouch ),
+ !!( bfrtf & bfrtfDBScan ) );
#endif // ENABLE_BFFTL_TRACING
- if ( FOSEventTraceEnabled< _etguidCacheRequestPage >() )
- {
+ if ( FOSEventTraceEnabled< _etguidCacheRequestPage >() )
+ {
#ifndef ENABLE_BFFTL_TRACING
- GetCurrUserTraceContext getutc;
- const BYTE bClientType = getutc->context.nClientType;
+ GetCurrUserTraceContext getutc;
+ const BYTE bClientType = getutc->context.nClientType;
#endif
- OSEventTrace_(
- _etguidCacheRequestPage,
- 10,
- &tickTouch,
- &(pbf->ifmp),
- &(pbf->pgno),
- &bflf,
- &( ( (CPAGE::PGHDR *)( pbf->pv ) )->objidFDP ),
- &( ( (CPAGE::PGHDR *)( pbf->pv ) )->fFlags ),
- &bflt,
- &pctPriority,
- &bfrtf,
- &bClientType );
+
+ OSEventTrace_(
+ _etguidCacheRequestPage,
+ 10,
+ &tickTouch,
+ &( pbf->ifmp ),
+ &( pbf->pgno ),
+ &bflf,
+ &( ( (CPAGE::PGHDR*) ( pbf->pv ) )->objidFDP ),
+ &( ( (CPAGE::PGHDR*) ( pbf->pv ) )->fFlags ),
+ &bflt,
+ &pctPriority,
+ &bfrtf,
+ &bClientType );
+ }
}
}
@@ -6393,11 +6446,14 @@ INLINE void BFITraceMarkPageAsSuperCold(
const IFMP ifmp,
const PGNO pgno )
{
+ if ( !FBFIDoNotEmitBfResMgrPageTrace( ifmp, pgno ) )
+ {
#ifdef ENABLE_BFFTL_TRACING
- (void)ErrBFIFTLMarkAsSuperCold( ifmp, pgno );
+ ( void )ErrBFIFTLMarkAsSuperCold( ifmp, pgno );
#endif // ENABLE_BFFTL_TRACING
- ETMarkPageAsSuperCold( TickOSTimeCurrent(), ifmp, pgno );
+ ETMarkPageAsSuperCold( TickOSTimeCurrent(), ifmp, pgno );
+ }
}
INLINE void BFITraceEvictPage(
@@ -6407,15 +6463,18 @@ INLINE void BFITraceEvictPage(
const ERR errBF,
const ULONG bfef )
{
- const ULONG pctPriority = 0; // Not relevant for eviction anymore.
-
+ if ( !FBFIDoNotEmitBfResMgrPageTrace( ifmp, pgno ) )
+ {
+ const ULONG pctPriority = 0; // Not relevant for eviction anymore.
+
#ifdef ENABLE_BFFTL_TRACING
- (void)ErrBFIFTLEvict( ifmp, pgno, fCurrentVersion, errBF, bfef, pctPriority );
+ ( void )ErrBFIFTLEvict( ifmp, pgno, fCurrentVersion, errBF, bfef, pctPriority );
#endif // ENABLE_BFFTL_TRACING
- const TICK tickEvictPage = TickOSTimeCurrent();
+ const TICK tickEvictPage = TickOSTimeCurrent();
- ETCacheEvictPage( tickEvictPage, ifmp, pgno, fCurrentVersion, errBF, bfef, pctPriority );
+ ETCacheEvictPage( tickEvictPage, ifmp, pgno, fCurrentVersion, errBF, bfef, pctPriority );
+ }
}
INLINE void BFITraceDirtyPage(
@@ -6423,50 +6482,53 @@ INLINE void BFITraceDirtyPage(
const BFDirtyFlags bfdf,
const TraceContext& tc )
{
- auto tick = TickOSTimeCurrent();
- static_assert( sizeof(tick) == sizeof(DWORD), "Compiler magic failing." );
- // Note that pbf->lgposModify contains the current lgposModify of the buffer, prior
- // to it being updated to reflect the new lgposModify that is triggering the dirty
- // operation. Each setting of lgposModify will generate its own trace so that is
- // more suitable to determine the lgpos associated with the dirty operation.
+ if ( !FBFIDoNotEmitBfResMgrPageTrace( pbf->ifmp, pbf->pgno ) )
+ {
+ auto tick = TickOSTimeCurrent();
+ static_assert( sizeof( tick ) == sizeof( DWORD ), "Compiler magic failing." );
+
+ // Note that pbf->lgposModify contains the current lgposModify of the buffer, prior
+ // to it being updated to reflect the new lgposModify that is triggering the dirty
+ // operation. Each setting of lgposModify will generate its own trace so that is
+ // more suitable to determine the lgpos associated with the dirty operation.
- // Need to read atomically because removing undo info may change it from under us
- // without a latch.
+ // Need to read atomically because removing undo info may change it from under us
+ // without a latch.
- const LGPOS lgposModifyRead = pbf->lgposModify.LgposAtomicRead();
- const ULONG lgposModifyLGen = (ULONG)lgposModifyRead.lGeneration;
- const USHORT lgposModifyISec = lgposModifyRead.isec;
- const USHORT lgposModifyIb = lgposModifyRead.ib;
+ const LGPOS lgposModifyRead = pbf->lgposModify.LgposAtomicRead();
+ const ULONG lgposModifyLGen = (ULONG) lgposModifyRead.lGeneration;
+ const USHORT lgposModifyISec = lgposModifyRead.isec;
+ const USHORT lgposModifyIb = lgposModifyRead.ib;
- Assert( (LONG)lgposModifyLGen == lgposModifyRead.lGeneration );
+ Assert( (LONG) lgposModifyLGen == lgposModifyRead.lGeneration );
#ifdef ENABLE_BFFTL_TRACING
- (void)ErrBFIFTLDirty( pbf->ifmp, pbf->pgno, bfdf, lgposModifyLGen, lgposModifyISec, lgposModifyIb );
+ ( void )ErrBFIFTLDirty( pbf->ifmp, pbf->pgno, bfdf, lgposModifyLGen, lgposModifyISec, lgposModifyIb );
#endif // ENABLE_BFFTL_TRACING
- Assert( CmpLgpos( pbf->lgposModify.LgposAtomicRead(), lgposModifyRead ) >= 0 );
+ Assert( CmpLgpos( pbf->lgposModify.LgposAtomicRead(), lgposModifyRead ) >= 0 );
- const CPAGE::PGHDR * ppghdr = (const CPAGE::PGHDR *)pbf->pv;
- GetCurrUserTraceContext getutc;
+ const CPAGE::PGHDR* ppghdr = (const CPAGE::PGHDR*) pbf->pv;
+ GetCurrUserTraceContext getutc;
- // Iorp() is reserved for the loweset level action that caused an IO, just above the IO layer (e.g. BF's reason for initiating an IO).
- // Dirtying a page isn't going to cause an IO directly, so iorp should be none. But it doesn't hurt telemetry if we do emit an iorp here.
- // These are some of the culprits who push an iorp because they call the IO layer directly, which expects an iorp.
- // But they also end up leaking iorp into the BF Api.
- // FUTURE-2022-04-14-SOMEONE - If we ever save tc on the BF, consider fixing the iorp leak.
- Expected( tc.iorReason.Iorp() == iorpNone ||
- tc.iorReason.Iorp() == iorpDatabaseShrink ||
- tc.iorReason.Iorp() == iorpDatabaseTrim ||
- tc.iorReason.Iorp() == iorpPatchFix ||
- tc.iorReason.Iorp() == iorpSPDatabaseInlineZero ||
- tc.iorReason.Iorp() == iorpBFLatch ); // page patch
-
- if ( pbf->bfdf < bfdfDirty /* first "proper" dirty */ )
- {
- // There is no point in logging itagMicFree, cbfree, dbtime because they would be the
- // same as the most recent read page trace at this point.
- ETCacheFirstDirtyPage(
+ // Iorp() is reserved for the loweset level action that caused an IO, just above the IO layer (e.g. BF's reason for initiating an IO).
+ // Dirtying a page isn't going to cause an IO directly, so iorp should be none. But it doesn't hurt telemetry if we do emit an iorp here.
+ // These are some of the culprits who push an iorp because they call the IO layer directly, which expects an iorp.
+ // But they also end up leaking iorp into the BF Api.
+ // FUTURE-2022-04-14-SOMEONE - If we ever save tc on the BF, consider fixing the iorp leak.
+ Expected( tc.iorReason.Iorp() == iorpNone ||
+ tc.iorReason.Iorp() == iorpDatabaseShrink ||
+ tc.iorReason.Iorp() == iorpDatabaseTrim ||
+ tc.iorReason.Iorp() == iorpPatchFix ||
+ tc.iorReason.Iorp() == iorpSPDatabaseInlineZero ||
+ tc.iorReason.Iorp() == iorpBFLatch ); // page patch
+
+ if ( pbf->bfdf < bfdfDirty /* first "proper" dirty */ )
+ {
+ // There is no point in logging itagMicFree, cbfree, dbtime because they would be the
+ // same as the most recent read page trace at this point.
+ ETCacheFirstDirtyPage(
tick,
pbf->ifmp,
pbf->pgno,
@@ -6486,9 +6548,9 @@ INLINE void BFITraceDirtyPage(
tc.iorReason.Ioru(),
tc.iorReason.Iorf(),
tc.nParentObjectClass );
- }
+ }
- ETCacheDirtyPage(
+ ETCacheDirtyPage(
tick,
pbf->ifmp,
pbf->pgno,
@@ -6508,85 +6570,92 @@ INLINE void BFITraceDirtyPage(
tc.iorReason.Ioru(),
tc.iorReason.Iorf(),
tc.nParentObjectClass );
+ }
}
INLINE void BFITraceSetLgposModify(
const PBF pbf,
const LGPOS& lgposModify )
{
- auto tick = TickOSTimeCurrent();
- static_assert( sizeof(tick) == sizeof(DWORD), "Compiler magic failing." );
+ if ( !FBFIDoNotEmitBfResMgrPageTrace( pbf->ifmp, pbf->pgno ) )
+ {
+ auto tick = TickOSTimeCurrent();
+ static_assert( sizeof( tick ) == sizeof( DWORD ), "Compiler magic failing." );
#ifdef ENABLE_BFFTL_TRACING
- const ULONG lgposModifyLGen = (ULONG)lgposModify.lGeneration;
- const USHORT lgposModifyISec = lgposModify.isec;
- const USHORT lgposModifyIb = lgposModify.ib;
+ const ULONG lgposModifyLGen = (ULONG) lgposModify.lGeneration;
+ const USHORT lgposModifyISec = lgposModify.isec;
+ const USHORT lgposModifyIb = lgposModify.ib;
- Assert( (LONG)lgposModifyLGen == lgposModify.lGeneration );
+ Assert( (LONG) lgposModifyLGen == lgposModify.lGeneration );
- (void)ErrBFIFTLSetLgposModify( pbf->ifmp, pbf->pgno, lgposModifyLGen, lgposModifyISec, lgposModifyIb );
+ (void) ErrBFIFTLSetLgposModify( pbf->ifmp, pbf->pgno, lgposModifyLGen, lgposModifyISec, lgposModifyIb );
#endif // ENABLE_BFFTL_TRACING
- ETCacheSetLgposModify(
+ ETCacheSetLgposModify(
tick,
pbf->ifmp,
pbf->pgno,
lgposModify.qw );
+ }
}
INLINE void BFITraceWritePage(
const PBF pbf,
const FullTraceContext& tc )
{
- const ULONG bfdfTrace = (ULONG)pbf->bfdf; // We need to put this on the stack because & isn't valid on a bitfield
- auto tick = TickOSTimeCurrent();
+ if ( !FBFIDoNotEmitBfResMgrPageTrace( pbf->ifmp, pbf->pgno ) )
+ {
+ const ULONG bfdfTrace = (ULONG) pbf->bfdf; // We need to put this on the stack because & isn't valid on a bitfield
+ auto tick = TickOSTimeCurrent();
- Assert( tc.etc.iorReason.Iorp() != iorpNone );
+ Assert( tc.etc.iorReason.Iorp() != iorpNone );
#ifdef ENABLE_BFFTL_TRACING
- // Update: Now that we're FTL logging from the IO completion, it can cause IO issue
- // and sync complete below the existing completion:
- // ese!OSSYNC::CLockDeadlockDetectionInfo::AssertCleanApiExit+0xd4 [d:\src\e16\esemulti\sources\dev\ese\published\inc\sync.hxx @ 3408]
- // ese!OSDiskIIOThreadCompleteWithErr+0x8a6 [d:\src\e16\esemulti\sources\dev\ese\src\os\osdisk.cxx @ 6984]
- // ese!COSFile::ErrIOAsync+0x6ef [d:\src\e16\esemulti\sources\dev\ese\src\os\osfile.cxx @ 1811]
- // ese!COSFile::ErrIOWrite+0x2c2 [d:\src\e16\esemulti\sources\dev\ese\src\os\osfile.cxx @ 1111]
- // ese!CFastTraceLog::ErrFTLIFlushBuffer+0x9fb [d:\src\e16\esemulti\sources\dev\ese\src\os\trace.cxx @ 2461]
- // ese!CFastTraceLog::ErrFTLFlushBuffer+0x3d [d:\src\e16\esemulti\sources\dev\ese\src\os\trace.cxx @ 2494]
- // ese!CFastTraceLogBuffer::ErrFTLBTrace+0x2b6 [d:\src\e16\esemulti\distrib\private\inc\trace.hxx @ 598]
- // ese!CFastTraceLog::ErrFTLTrace+0x90 [d:\src\e16\esemulti\sources\dev\ese\src\os\trace.cxx @ 2524]
- // ese!ErrBFIFTLWrite+0xc7 [d:\src\e16\esemulti\sources\dev\ese\published\inc\bf\bfftl.hxx @ 337]
- // ese!BFITraceWritePage+0x111 [d:\src\e16\esemulti\sources\dev\ese\src\ese\bf.cxx @ 6035]
- // ese!BFIAsyncWriteComplete+0xc1 [d:\src\e16\esemulti\sources\dev\ese\src\ese\bf.cxx @ 25254]
- // ese!COSFile::IOComplete+0xe5 [d:\src\e16\esemulti\sources\dev\ese\src\os\osfile.cxx @ 1592]
- // ese!COSFile::IOComplete_+0x26 [d:\src\e16\esemulti\sources\dev\ese\src\os\osfile.cxx @ 1565]
- // ese!OSDiskIIOThreadCompleteWithErr+0x907 [d:\src\e16\esemulti\sources\dev\ese\src\os\osdisk.cxx @ 6999]
- // ese!OSDiskIIOThreadIComplete+0x150 [d:\src\e16\esemulti\sources\dev\ese\src\os\osdisk.cxx @ 7047]
- // ese!CTaskManager::TMIDispatch+0x800 [d:\src\e16\esemulti\sources\dev\ese\src\os\task.cxx @ 766]
- // Ultimately this could be fixed by [re]moving FTL tracing off the existing IO mechanism and using
- // it's own NT API writing calls, which would also fix the other issue in ErrBFIPrereadPage() at the
- // same time.
- //(void)ErrBFIFTLWrite( pbf->ifmp, pbf->pgno, BFDirtyFlags( pbf->bfdf ), iorp );
+ // Update: Now that we're FTL logging from the IO completion, it can cause IO issue
+ // and sync complete below the existing completion:
+ // ese!OSSYNC::CLockDeadlockDetectionInfo::AssertCleanApiExit+0xd4 [d:\src\e16\esemulti\sources\dev\ese\published\inc\sync.hxx @ 3408]
+ // ese!OSDiskIIOThreadCompleteWithErr+0x8a6 [d:\src\e16\esemulti\sources\dev\ese\src\os\osdisk.cxx @ 6984]
+ // ese!COSFile::ErrIOAsync+0x6ef [d:\src\e16\esemulti\sources\dev\ese\src\os\osfile.cxx @ 1811]
+ // ese!COSFile::ErrIOWrite+0x2c2 [d:\src\e16\esemulti\sources\dev\ese\src\os\osfile.cxx @ 1111]
+ // ese!CFastTraceLog::ErrFTLIFlushBuffer+0x9fb [d:\src\e16\esemulti\sources\dev\ese\src\os\trace.cxx @ 2461]
+ // ese!CFastTraceLog::ErrFTLFlushBuffer+0x3d [d:\src\e16\esemulti\sources\dev\ese\src\os\trace.cxx @ 2494]
+ // ese!CFastTraceLogBuffer::ErrFTLBTrace+0x2b6 [d:\src\e16\esemulti\distrib\private\inc\trace.hxx @ 598]
+ // ese!CFastTraceLog::ErrFTLTrace+0x90 [d:\src\e16\esemulti\sources\dev\ese\src\os\trace.cxx @ 2524]
+ // ese!ErrBFIFTLWrite+0xc7 [d:\src\e16\esemulti\sources\dev\ese\published\inc\bf\bfftl.hxx @ 337]
+ // ese!BFITraceWritePage+0x111 [d:\src\e16\esemulti\sources\dev\ese\src\ese\bf.cxx @ 6035]
+ // ese!BFIAsyncWriteComplete+0xc1 [d:\src\e16\esemulti\sources\dev\ese\src\ese\bf.cxx @ 25254]
+ // ese!COSFile::IOComplete+0xe5 [d:\src\e16\esemulti\sources\dev\ese\src\os\osfile.cxx @ 1592]
+ // ese!COSFile::IOComplete_+0x26 [d:\src\e16\esemulti\sources\dev\ese\src\os\osfile.cxx @ 1565]
+ // ese!OSDiskIIOThreadCompleteWithErr+0x907 [d:\src\e16\esemulti\sources\dev\ese\src\os\osdisk.cxx @ 6999]
+ // ese!OSDiskIIOThreadIComplete+0x150 [d:\src\e16\esemulti\sources\dev\ese\src\os\osdisk.cxx @ 7047]
+ // ese!CTaskManager::TMIDispatch+0x800 [d:\src\e16\esemulti\sources\dev\ese\src\os\task.cxx @ 766]
+ // Ultimately this could be fixed by [re]moving FTL tracing off the existing IO mechanism and using
+ // it's own NT API writing calls, which would also fix the other issue in ErrBFIPrereadPage() at the
+ // same time.
+ //(void)ErrBFIFTLWrite( pbf->ifmp, pbf->pgno, BFDirtyFlags( pbf->bfdf ), iorp );
#endif // ENABLE_BFFTL_TRACING
- ETCacheWritePage(
- tick,
- pbf->ifmp,
- pbf->pgno,
- (((CPAGE::PGHDR *)(pbf->pv))->objidFDP),
- (((CPAGE::PGHDR *)(pbf->pv))->fFlags),
- bfdfTrace,
- tc.utc.context.dwUserID,
- tc.utc.context.nOperationID,
- tc.utc.context.nOperationType,
- tc.utc.context.nClientType,
- tc.utc.context.fFlags,
- tc.utc.dwCorrelationID,
- tc.etc.iorReason.Iorp(),
- tc.etc.iorReason.Iors(),
- tc.etc.iorReason.Iort(),
- tc.etc.iorReason.Ioru(),
- tc.etc.iorReason.Iorf(),
- tc.etc.nParentObjectClass );
+ ETCacheWritePage(
+ tick,
+ pbf->ifmp,
+ pbf->pgno,
+ ( ( (CPAGE::PGHDR*) ( pbf->pv ) )->objidFDP ),
+ ( ( (CPAGE::PGHDR*) ( pbf->pv ) )->fFlags ),
+ bfdfTrace,
+ tc.utc.context.dwUserID,
+ tc.utc.context.nOperationID,
+ tc.utc.context.nOperationType,
+ tc.utc.context.nClientType,
+ tc.utc.context.fFlags,
+ tc.utc.dwCorrelationID,
+ tc.etc.iorReason.Iorp(),
+ tc.etc.iorReason.Iors(),
+ tc.etc.iorReason.Iort(),
+ tc.etc.iorReason.Ioru(),
+ tc.etc.iorReason.Iorf(),
+ tc.etc.nParentObjectClass );
+ }
}
@@ -9724,7 +9793,7 @@ VOID CBFIssueList::NullifyDiskTiltFake( const IFMP ifmp )
}
-CCriticalSection CBFIssueList::s_critSync( CLockBasicInfo( CSyncBasicInfo( _T( "CBFIssueList::s_critSync" ) ), rankBFIssueListSync, 0 ) );
+CCriticalSection CBFIssueList::s_critSync( CLockBasicInfo( CSyncBasicInfo( "CBFIssueList::s_critSync" ), rankBFIssueListSync, 0 ) );
CMeteredSection CBFIssueList::s_msSync;
@@ -9749,7 +9818,7 @@ HMEMORY_NOTIFICATION g_pMemoryNotification = NULL;
// Init / Term
-LOCAL CBinaryLock g_blBFMaintScheduleCancel( CLockBasicInfo( CSyncBasicInfo( _T( "BFMaint Schedule/Cancel" ) ), rankBFMaintScheduleCancel, 0 ) );
+LOCAL CBinaryLock g_blBFMaintScheduleCancel( CLockBasicInfo( CSyncBasicInfo( "BFMaint Schedule/Cancel" ), rankBFMaintScheduleCancel, 0 ) );
LOCAL volatile BOOL g_fBFMaintInitialized = fFalse;
ERR ErrBFIMaintInit()
@@ -10121,8 +10190,8 @@ INLINE void BFISynchronicity( void )
// Avail Pool
-CSemaphore g_semMaintAvailPoolRequestUrgent( CSyncBasicInfo( _T( "g_semMaintAvailPoolRequestUrgent" ) ) );
-CSemaphore g_semMaintAvailPoolRequest( CSyncBasicInfo( _T( "g_semMaintAvailPoolRequest" ) ) );
+CSemaphore g_semMaintAvailPoolRequestUrgent( CSyncBasicInfo( "g_semMaintAvailPoolRequestUrgent" ) );
+CSemaphore g_semMaintAvailPoolRequest( CSyncBasicInfo( "g_semMaintAvailPoolRequest" ) );
LONG_PTR cbfAvailPoolLow;
LONG_PTR cbfAvailPoolHigh;
@@ -10322,7 +10391,7 @@ void BFIMaintAvailPoolITask( void*, void* )
// Scavenging
-CSemaphore g_semMaintScavenge( CSyncBasicInfo( _T( "g_semMaintScavenge" ) ) );
+CSemaphore g_semMaintScavenge( CSyncBasicInfo( "g_semMaintScavenge" ) );
// We track the last several runs
@@ -11149,8 +11218,14 @@ ERR ErrBFIMaintScavengeIScavengePages( const char* const szContextTraceOnly, con
}
// Async-flush this page.
+ //
+ // NOTE: this can block if ulScavengeWriteSev == ulScavengeWriteMax which would give us qosIODispatchImmediate
const IOREASON ior = IOR( ( ( bfefReason == bfefReasonShrink ) ? iorpBFShrink : iorpBFAvailPool ), fSync ? iorfForeground : iorfNone );
const OSFILEQOS qos = QosBFIMaintScavengePages( UlParam( PinstFromIfmp( pbf->ifmp ), JET_paramIOPriority ), ulScavengeWriteSev );
+ if ( ( qos & qosIODispatchMask ) == qosIODispatchImmediate )
+ {
+ (void)bfil.ErrIssue( fFalse );
+ }
const ERR errFlush = ErrBFIFlushPage( pbf, ior, qos, bfdfDirty, fFalse /* fOpportune */, &fPermanentErr );
// Count the number of latched pages we see.
@@ -11771,7 +11846,7 @@ void BFIMaintScavengeTerm( void )
// Checkpoint Depth
-CSemaphore g_semMaintCheckpointDepthRequest( CSyncBasicInfo( _T( "g_semMaintCheckpointDepthRequest" ) ) );
+CSemaphore g_semMaintCheckpointDepthRequest( CSyncBasicInfo( "g_semMaintCheckpointDepthRequest" ) );
IFMP g_ifmpMaintCheckpointDepthStart;
@@ -13336,7 +13411,7 @@ ERR ErrBFIMaintCheckpointDepthIFlushPagesByIFMP( const IFMP ifmp, BOOL * const p
// Checkpoint
-CSemaphore g_semMaintCheckpointRequest( CSyncBasicInfo( _T( "g_semMaintCheckpointRequest" ) ) );
+CSemaphore g_semMaintCheckpointRequest( CSyncBasicInfo( "g_semMaintCheckpointRequest" ) );
TICK g_tickMaintCheckpointLast;
@@ -13870,9 +13945,9 @@ void BFIMaintHashedLatchesIRedistribute()
// Cache Size
-CSemaphore g_semMaintCacheStatsRequest( CSyncBasicInfo( _T( "g_semMaintCacheStatsRequest" ) ) );
+CSemaphore g_semMaintCacheStatsRequest( CSyncBasicInfo( "g_semMaintCacheStatsRequest" ) );
-CSemaphore g_semMaintCacheSize( CSyncBasicInfo( _T( "g_semMaintCacheSize" ) ) );
+CSemaphore g_semMaintCacheSize( CSyncBasicInfo( "g_semMaintCacheSize" ) );
LONG g_cMaintCacheSizePending = 0;
inline ICBPage IcbBFIBufferSize( _In_ const INT cbSize )
@@ -14533,7 +14608,7 @@ void BFIMaintCacheStatsITask( VOID *, VOID * pvContext )
// we've failed to acquire the semaphore to schedule the task. this means the task must be executing
// right now or in the process of rescheduling itself to complete its job.
- S_ASSERT( dtickMaintCacheSizeRequest <= ( dtickMaintCacheStatsPeriod / 2 ) );
+ static_assert( dtickMaintCacheSizeRequest <= ( dtickMaintCacheStatsPeriod / 2 ) );
g_cMaintCacheSizeReqAcquireFailures++;
@@ -15080,7 +15155,7 @@ TICK DtickBFIMaintCacheSizeDuration()
// Idle Database
-CSemaphore g_semMaintIdleDatabaseRequest( CSyncBasicInfo( _T( "g_semMaintIdleDatabaseRequest" ) ) );
+CSemaphore g_semMaintIdleDatabaseRequest( CSyncBasicInfo( "g_semMaintIdleDatabaseRequest" ) );
TICK g_tickMaintIdleDatabaseLast;
@@ -23220,23 +23295,34 @@ void BFIPurgeAllPageVersions( _Inout_ BFLatch* const pbfl, const TraceContext& t
g_critBFDepend.Enter();
for ( PBF pbfAbandon = pbf->pbfTimeDepChainNext; pbfAbandon != pbfNil; )
{
+ BOOL fRetry = fFalse;
+
if ( pbfAbandon->sxwl.ErrTryAcquireExclusiveLatch() == CSXWLatch::ERR::errSuccess )
{
if ( !pbfAbandon->fAbandoned )
{
- pbfAbandon->sxwl.UpgradeExclusiveLatchToWriteLatch();
- pbfAbandon->fAbandoned = fTrue;
- pbfAbandon->sxwl.ReleaseWriteLatch();
+ if ( pbfAbandon->sxwl.ErrTryUpgradeExclusiveLatchToWriteLatch() == CSXWLatch::ERR::errSuccess )
+ {
+ pbfAbandon->fAbandoned = fTrue;
+ pbfAbandon->sxwl.ReleaseWriteLatch();
+ }
+ else
+ {
+ fRetry = fTrue;
+ pbfAbandon->sxwl.ReleaseExclusiveLatch();
+ }
}
else
{
pbfAbandon->sxwl.ReleaseExclusiveLatch();
}
-
- // Next in the chain.
- pbfAbandon = pbfAbandon->pbfTimeDepChainNext;
}
else
+ {
+ fRetry = fTrue;
+ }
+
+ if ( fRetry )
{
// Avoid deadlocks.
g_critBFDepend.Leave();
@@ -23246,6 +23332,11 @@ void BFIPurgeAllPageVersions( _Inout_ BFLatch* const pbfl, const TraceContext& t
// Reset enumeration because we left the g_critBFDepend for an instant.
pbfAbandon = pbf->pbfTimeDepChainNext;
}
+ else
+ {
+ // Next in the chain.
+ pbfAbandon = pbfAbandon->pbfTimeDepChainNext;
+ }
}
g_critBFDepend.Leave();
@@ -24013,7 +24104,9 @@ ERR ErrBFIFlushLog( _In_ const IFMP ifmp, _In_ const IOFLUSHREASON iofr, const B
// I/O
-const void* const PV_IO_CTX_LOCK = (void*)upMax;
+const void* const PV_IO_CTX_TICK_FLAG = (void*)(ULONG_PTR)1;
+const void* const PV_IO_CTX_LOCK = (void*)( upMax & ~( (ULONG_PTR)PV_IO_CTX_TICK_FLAG ) );
+
void* PvBFIAcquireIOContext( PBF pbf )
{
void* pvIOContextOld = AtomicReadPointer( &pbf->pvIOContext );
@@ -24102,6 +24195,36 @@ void BFIResetIOContext( PBF pbf )
}
}
+void BFISetAsyncIOContext( _In_ const PBF pbf, _In_ void* const pvIOContextNew )
+{
+ Assert( !( (ULONG_PTR)pvIOContextNew & (ULONG_PTR)PV_IO_CTX_TICK_FLAG ) );
+
+ BFISetIOContext( pbf, pvIOContextNew );
+}
+
+void BFIResetAsyncIOContext( _In_ const PBF pbf )
+{
+ BFIResetIOContext( pbf );
+}
+
+TICK TickBFISyncIOContextStartTime()
+{
+ return (TICK)( (ULONG_PTR)TickOSTimeInterruptCurrent() | (ULONG_PTR)PV_IO_CTX_TICK_FLAG );
+}
+
+void BFISetSyncIOContext( _In_ const PBF pbf )
+{
+ void* const pvIOContextNew = (void*)(ULONG_PTR)TickBFISyncIOContextStartTime();
+ Assert( (ULONG_PTR)pvIOContextNew & (ULONG_PTR)PV_IO_CTX_TICK_FLAG );
+
+ BFISetIOContext( pbf, pvIOContextNew );
+}
+
+void BFIResetSyncIOContext( _In_ const PBF pbf )
+{
+ BFIResetIOContext( pbf );
+}
+
BOOL FBFIIsIOHung( PBF pbf )
{
void* const pvIOContext = PvBFIAcquireIOContext( pbf );
@@ -24121,12 +24244,14 @@ BYTE PctBFIIsIOHung( PBF pbf, void* const pvIOContext )
{
IFileAPI* const pfapi = g_rgfmp[ pbf->ifmp ].Pfapi();
- const TICK dtickIOElapsed = pfapi->DtickIOElapsed( pvIOContext );
+ const TICK dtickIOElapsed = ( (ULONG_PTR)pvIOContext & (ULONG_PTR)PV_IO_CTX_TICK_FLAG ) ?
+ DtickDelta( (TICK)(ULONG_PTR)pvIOContext, TickBFISyncIOContextStartTime() ) :
+ pfapi->DtickIOElapsed( pvIOContext );
const TICK dtickHungIO = (TICK)UlParam( JET_paramHungIOThreshold );
if ( dtickIOElapsed >= dtickHungIO )
{
- return 100;
+ return IsDebuggerAttached() ? 99 : 100;
}
else
{
@@ -24276,14 +24401,17 @@ void BFISyncRead( PBF pbf, const OSFILEQOS qosIoPriorities, const TraceContext&
if ( !FBFICacheViewCacheDerefIo( pbf ) )
{
HRT hrtStart = HrtHRTCount();
+
+ BFISetSyncIOContext( pbf );
+
err = pfapi->ErrIORead( tc,
ibOffset,
cbData,
pbData,
- qosIoUserDispatch | qosIOSignalSlowSyncIO,
- NULL, // Passing a NULL pfnCompletion triggers sync I/O (foreground on this thread).
- DWORD_PTR( pbf ),
- IFileAPI::PfnIOHandoff( BFISyncReadHandoff ) );
+ qosIoUserDispatch | qosIOSignalSlowSyncIO );
+
+ BFIResetSyncIOContext( pbf );
+
BFITrackCacheMissLatency( pbf, hrtStart, ( tc.iorReason.Iorf() & iorfReclaimPageFromOS ) ? bftcmrReasonPagingFaultDb : bftcmrReasonSyncRead, qosIoPriorities, tc, err );
Ptls()->threadstats.cPageRead++;
}
@@ -24295,21 +24423,6 @@ void BFISyncRead( PBF pbf, const OSFILEQOS qosIoPriorities, const TraceContext&
}
-void BFISyncReadHandoff( const ERR err,
- IFileAPI* const pfapi,
- const FullTraceContext& tc,
- const OSFILEQOS grbitQOS,
- const QWORD ibOffset,
- const DWORD cbData,
- const BYTE* const pbData,
- const PBF pbf,
- void* const pvIOContext )
-{
- Assert( JET_errSuccess == err ); // Yeah!!!
-
- BFISetIOContext( pbf, pvIOContext );
-}
-
void BFISyncReadComplete( const ERR err,
IFileAPI* const pfapi,
const OSFILEQOS grbitQOS,
@@ -24321,17 +24434,6 @@ void BFISyncReadComplete( const ERR err,
{
Assert( pbf->sxwl.FOwnWriteLatch() );
- // reset the I/O context, since the operation is officially completed.
-
- if ( AtomicReadPointer( &pbf->pvIOContext ) != NULL )
- {
- BFIResetIOContext( pbf );
- }
- else
- {
- Assert( FBFICacheViewCacheDerefIo( pbf ) );
- }
-
// read was successful
if ( err >= 0 )
@@ -24506,10 +24608,9 @@ void BFIAsyncReadHandoff( const ERR err,
void* const pvIOContext )
{
Assert( JET_errSuccess == err ); // Yeah!!!
-
if ( pvIOContext != NULL )
{
- BFISetIOContext( pbf, pvIOContext );
+ BFISetAsyncIOContext( pbf, pvIOContext );
}
else
{
@@ -24539,7 +24640,7 @@ void BFIAsyncReadComplete( const ERR err,
if ( AtomicReadPointer( &pbf->pvIOContext ) != NULL )
{
- BFIResetIOContext( pbf );
+ BFIResetAsyncIOContext( pbf );
}
else
{
@@ -24648,14 +24749,15 @@ ERR ErrBFISyncWrite( PBF pbf, const BFLatchType bfltHave, OSFILEQOS qos, const T
// issue sync write
+ BFISetSyncIOContext( pbf );
+
err = pfapi->ErrIOWrite( tc,
ibOffset,
cbData,
pbData,
- qos,
- NULL, // Passing a NULL pfnCompletion triggers sync I/O (foreground on this thread).
- DWORD_PTR( pbf ),
- IFileAPI::PfnIOHandoff( BFISyncWriteHandoff ) );
+ qos );
+
+ BFIResetSyncIOContext( pbf );
// complete sync write
@@ -24666,21 +24768,6 @@ ERR ErrBFISyncWrite( PBF pbf, const BFLatchType bfltHave, OSFILEQOS qos, const T
return err;
}
-void BFISyncWriteHandoff( const ERR err,
- IFileAPI* const pfapi,
- const FullTraceContext& tc,
- const OSFILEQOS grbitQOS,
- const QWORD ibOffset,
- const DWORD cbData,
- const BYTE* const pbData,
- const PBF pbf,
- void* const pvIOContext )
-{
- Assert( JET_errSuccess == err ); // Yeah!!!
-
- BFISetIOContext( pbf, pvIOContext );
-}
-
void BFISyncWriteComplete( const ERR err,
IFileAPI* const pfapi,
const FullTraceContext& tc,
@@ -24691,10 +24778,6 @@ void BFISyncWriteComplete( const ERR err,
const PBF pbf,
const BFLatchType bfltHave )
{
- // reset the I/O context, since the operation is officially completed.
-
- BFIResetIOContext( pbf );
-
// trace that we have just written a page
BFITraceWritePage( pbf, tc );
@@ -24891,8 +24974,7 @@ void BFIAsyncWriteHandoff( const ERR err,
void* const pvIOContext )
{
Assert( JET_errSuccess == err ); // Yeah!!!
-
- BFISetIOContext( pbf, pvIOContext );
+ BFISetAsyncIOContext( pbf, pvIOContext );
Enforce( CmpLgpos( pbf->lgposModify, g_rgfmp[ pbf->ifmp ].LgposWaypoint() ) <= 0 ); // just for insurance
@@ -25498,7 +25580,7 @@ void BFIAsyncWriteComplete( const ERR err,
// reset the I/O context, since the operation is officially completed.
- BFIResetIOContext( pbf );
+ BFIResetAsyncIOContext( pbf );
// trace that we have just written a page
diff --git a/dev/ese/src/ese/bt.cxx b/dev/ese/src/ese/bt.cxx
index 2abe6172..24f5caf6 100644
--- a/dev/ese/src/ese/bt.cxx
+++ b/dev/ese/src/ese/bt.cxx
@@ -11313,6 +11313,7 @@ LOCAL ERR ErrBTIGetNewPages( FUCB *pfucb, SPLITPATH *psplitPathLeaf, DIRFLAG dir
CpgDIRActiveSpaceRequestReserve( pfucb ) != cpgDIRReserveConsumed &&
( ( psplit->fNewPageFlags & CPAGE::fPageLeaf ) || fVerticalToLeafSplit ) )
{
+
// If there is an active reserve request outstanding and this is a leaf page allocation,
// indicate to space to consume the active reserve.
fSPAllocFlags |= ( fSPContinuous | fSPUseActiveReserve );
@@ -13521,9 +13522,10 @@ ERR ErrBTIMultipageCleanup(
const BOOL fRightMerges,
__inout_opt PrereadInfo * const pPrereadInfo )
{
- ERR err;
+ ERR err = JET_errSuccess;
MERGEPATH *pmergePath = NULL;
- PIBTraceContextScope tcScope = TcBTICreateCtxScope( pfucb, iorsBTMerge );
+ PIBTraceContextScope tcScope = TcBTICreateCtxScope( pfucb, iorsBTMerge );
+ BOOL fValidBmNext = fFalse;
if ( pmergetype )
{
@@ -13534,27 +13536,12 @@ ERR ErrBTIMultipageCleanup(
{
// btree is scheduled for deletion - don't bother attempting cleanup
//
- if ( NULL != pbmNext )
- {
- pbmNext->key.suffix.SetCb( 0 );
- pbmNext->data.SetCb( 0 );
- }
-
- return JET_errSuccess;
+ goto HandleError;
}
// get path RIW latched
//
Call( ErrBTICreateMergePath( pfucb, bm, pgnoNull, fTrue, &pmergePath, pPrereadInfo ) );
- if ( wrnBTShallowTree == err )
- {
- if ( NULL != pbmNext )
- {
- pbmNext->key.suffix.SetCb( 0 );
- pbmNext->data.SetCb( 0 );
- }
- goto HandleError;
- }
// check if merge conditions hold
//
@@ -13564,16 +13551,15 @@ ERR ErrBTIMultipageCleanup(
if ( mergetypeEmptyTree == pmergePath->pmerge->mergetype )
{
- if ( NULL != pbmNext )
- {
- pbmNext->key.suffix.SetCb( 0 );
- pbmNext->data.SetCb( 0 );
- }
-
+ // This always releases pmergePath.
err = ErrBTIMergeEmptyTree( pfucb, pmergePath );
- return err;
+ pmergePath = NULL;
+
+ goto HandleError;
}
+ fValidBmNext = fTrue;
+
// release pages not involved in merge
//
BTIMergeReleaseUnneededPages( pmergePath );
@@ -13668,6 +13654,17 @@ ERR ErrBTIMultipageCleanup(
HandleError:
BTIReleaseMergePaths( pmergePath );
+
+ if ( ( pbmNext != NULL ) && ( !fValidBmNext || ( err < JET_errSuccess ) ) )
+ {
+ pbmNext->Reset();
+ }
+
+ if ( err == errBTShallowTree )
+ {
+ err = JET_errSuccess;
+ }
+
return err;
}
@@ -13933,7 +13930,7 @@ LOCAL ERR ErrBTICreateMergePath( FUCB *pfucb,
{
// tree is too shallow to bother doing merges on
//
- Error( ErrERRCheck( wrnBTShallowTree ) );
+ Error( ErrERRCheck( errBTShallowTree ) );
}
BOOL fLeftEdgeOfBtree = fTrue;
@@ -13999,7 +13996,7 @@ LOCAL ERR ErrBTICreateMergePath( FUCB *pfucb,
const MERGEPATH * const pmergePathParent = (*ppmergePath)->pmergePathParent;
// if root page was also a leaf page or the internal page we're looking for, we would have
- // err'd out above with wrnBTShallowTree
+ // err'd out above with errBTShallowTree
Assert( NULL != pmergePathParent );
Assert( !( pcsr->Cpage().FRootPage() ) );
@@ -14084,15 +14081,13 @@ LOCAL ERR ErrBTICreateMergePath( FUCB *pfucb,
#ifdef DEBUG
if ( err >= JET_errSuccess )
{
- if ( err != wrnBTShallowTree )
- {
- Assert( !!(*ppmergePath)->csr.Cpage().FLeafPage() == !!fLeafPage );
- }
- else
- {
- Assert( (*ppmergePath)->csr.Cpage().FRootPage() );
- }
+ Assert( !!(*ppmergePath)->csr.Cpage().FLeafPage() == !!fLeafPage );
}
+ else if ( err == errBTShallowTree )
+ {
+ Assert( (*ppmergePath)->csr.Cpage().FRootPage() );
+ }
+
#endif
return err;
@@ -14103,7 +14098,7 @@ LOCAL ERR ErrBTICreateMergePath( FUCB *pfucb,
LOCAL VOID BTIMergeCopyNextBookmark( FUCB * const pfucb,
MERGEPATH * const pmergePathLeaf,
BOOKMARK * const pbmNext,
- const BOOL fRightMerges )
+ const BOOL fRightMerges )
// ================================================================
//
// Copies next bookmark to seek for online defrag.
@@ -14136,8 +14131,7 @@ LOCAL VOID BTIMergeCopyNextBookmark( FUCB * const pfucb,
//
if ( pcsr->Pgno() == pgnoNull )
{
- pbmNext->key.suffix.SetCb( 0 );
- pbmNext->data.SetCb( 0 );
+ pbmNext->Reset();
return;
}
@@ -15760,9 +15754,9 @@ LOCAL VOID BTIUpdatePagePointer(
// ================================================================
LOCAL VOID BTIMovePageCopyNextBookmark(
- _In_ const FUCB * const pfucb,
+ _In_ const FUCB * const pfucb,
_In_ const MERGEPATH * const pmergePath,
- __inout BOOKMARK * const pbmNext )
+ _Inout_ BOOKMARK * const pbmNext )
// ================================================================
//
// copies the bookmark from the right-hand page for a move
@@ -15777,12 +15771,9 @@ LOCAL VOID BTIMovePageCopyNextBookmark(
Assert( pbmNext );
Assert( NULL != pbmNext->key.suffix.Pv() );
- if( pgnoNull == pmergePath->pmerge->csrRight.Pgno())
+ if ( pgnoNull == pmergePath->pmerge->csrRight.Pgno() )
{
- pbmNext->key.prefix.SetCb( 0 );
- pbmNext->key.suffix.SetCb( 0 );
- pbmNext->data.SetCb( 0 );
- Assert( pbmNext->key.FNull() );
+ pbmNext->Reset();
}
else
{
@@ -16060,6 +16051,7 @@ LOCAL ERR ErrBTIPageMove(
{
Call( ErrBTIMergeLatchSiblingPages( pfucb, pmergePath ) );
}
+
Call( ErrBTIPageMoveAllocatePage( pfucb, pmergePath, fSPAllocFlags, dirflag ) );
BTIMergeReleaseUnneededPages( pmergePath );
@@ -16139,7 +16131,7 @@ ERR ErrBTPageMove(
_In_ const PGNO pgnoSource,
_In_ const BOOL fLeafPage,
_In_ const ULONG fSPAllocFlags,
- __inout BOOKMARK * const pbmNext )
+ _Inout_ BOOKMARK * const pbmNext )
// ================================================================
{
Assert( pfucb );
@@ -16160,17 +16152,6 @@ ERR ErrBTPageMove(
}
Call( ErrBTICreateMergePath( pfucb, bm, pgnoSource, fLeafPage, &pmergePath ) );
- if ( wrnBTShallowTree == err )
- {
- if ( pbmNext )
- {
- pbmNext->key.prefix.SetCb( 0 );
- pbmNext->key.suffix.SetCb( 0 );
- pbmNext->data.SetCb( 0 );
- }
-
- goto HandleError;
- }
Call( ErrBTINewMerge( pmergePath ) );
pmergePath->pmerge->mergetype = mergetypePageMove;
@@ -16194,6 +16175,12 @@ ERR ErrBTPageMove(
HandleError:
BTIReleaseMergePaths( pmergePath );
Assert( !Pcsr( pfucb )->FLatched( ) );
+
+ if ( ( pbmNext != NULL ) && ( err < JET_errSuccess ) )
+ {
+ pbmNext->Reset();
+ }
+
return err;
}
@@ -16260,6 +16247,148 @@ VOID BTIPerformMerge( FUCB *pfucb, MERGEPATH *pmergePathLeaf )
}
}
+// ================================================================
+ERR ErrBTContiguousExtentMove(
+ _In_ FUCB * const pfucb,
+ _In_ const BOOKMARK& bm,
+ _In_ const PGNO pgnoSourceFirst,
+ _Out_ CPG * const pcpgMoved )
+// ================================================================
+{
+ Assert( pfucb );
+ Assert( !FFUCBSpace( pfucb ) );
+ Assert( !Pcsr( pfucb )->FLatched() );
+ Assert( !bm.key.FNull() );
+ Assert( pgnoSourceFirst != pgnoNull );
+
+ ERR err = JET_errSuccess;
+ PIBTraceContextScope tcScope = TcBTICreateCtxScope( pfucb, iorsBTMerge );
+ MERGEPATH * pmergePath = NULL;
+ EXTENTINFO extinfoOE;
+ BOOKMARK_BUFFER bmbCurr, bmbNext;
+ CPG cpgToMove = 0;
+ BOOL fActiveSpaceRequestReserveCreated = fFalse;
+
+ // We cannot keep whole portions of the data tree, as well as the space trees, locked during this operation.
+ // Therefore, we are going to run the discovery code below using the extent returned previously and without
+ // any locks, and we will, later, stop the extent move operation.
+ //
+
+ // Latch the path, from root to leaf.
+ Call( ErrBTICreateMergePath( pfucb, bm, pgnoSourceFirst, fTrue, &pmergePath ) );
+ Assert( pmergePath->csr.Cpage().PgnoThis() == pgnoSourceFirst );
+
+ // Get OE extent that hosts this page.
+ Call( ErrSPGetOwningExtent( pfucb, pgnoSourceFirst, &extinfoOE ) );
+ Assert( extinfoOE.FContainsPgno( pgnoSourceFirst ) );
+
+ // Find a contiguous run based on the pgnos found in the parent-of-leaf.
+ // Note that this will destroy the merge path, as the iline will be modified.
+ for ( MERGEPATH * const pmergePathParent = pmergePath->pmergePathParent;
+ pmergePathParent->csr.ILine() < pmergePathParent->csr.Cpage().Clines();
+ pmergePathParent->csr.IncrementILine() )
+ {
+ NDGet( pfucb, &pmergePathParent->csr );
+
+ Assert( sizeof( PGNO ) == pfucb->kdfCurr.data.Cb() );
+ const PGNO pgnoToMove = *( (UnalignedLittleEndian< PGNO > *)pfucb->kdfCurr.data.Pv() );
+ Assert( pgnoToMove != pgnoNull );
+ Assert( ( cpgToMove != 0 ) || ( pgnoToMove == pgnoSourceFirst ) ); // Cursor must be positioned in the first pgno.
+ Assert( ( cpgToMove != 1 ) || ( pgnoToMove == pmergePath->csr.Cpage().PgnoNext() ) ); // Second page is the right sibling of the first.
+
+ // Consider it part of a run if the page is within the same extent.
+ if ( extinfoOE.FContainsPgno( pgnoToMove ) )
+ {
+ cpgToMove++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ Assert( cpgToMove > 0 );
+
+ // Release latch path.
+ BTIReleaseMergePaths( pmergePath );
+ pmergePath = NULL;
+
+ // If we have only one page to move, fallback to single page move.
+ // If we have multiple pages to move, reserve the exact space needed and move one by one.
+ // Note that, because we don't keep everything latched, things might have changed underneath us, so
+ // do not try to enforce that the page layout hasn't change. Otherwise, we could end up with fragmented
+ // extents if we often stop too early. The exception is for the first page, which can bail out before
+ // any space is allocated, if we pass in an expected pgno (pgnoSourceFirst, in this case).
+ const BOOL fSinglePageMove = ( cpgToMove == 1 );
+ Call( bmbCurr.ErrAllocAndCopyKeyData( bm.key, bm.data ) );
+ Call( bmbNext.ErrAllocBuffer() );
+ bmbNext.NullifyAndSetPvsToBuffer();
+ for ( CPG cpgMoved = 0; ( cpgMoved < cpgToMove ) && !bmbCurr.Bm().FNull(); cpgMoved++ )
+ {
+ const BOOL fFirstPage = ( cpgMoved == 0 );
+ const BOOL fUseActiveSpaceRequestReserve = !fSinglePageMove;
+ const BOOL fCreateActiveSpaceRequestReserve = ( fUseActiveSpaceRequestReserve && fFirstPage );
+
+ if ( fCreateActiveSpaceRequestReserve )
+ {
+ DIRSetActiveSpaceRequestReserve( pfucb, cpgToMove - 1 );
+ fActiveSpaceRequestReserveCreated = fTrue;
+ }
+
+ err = ErrBTPageMove(
+ pfucb,
+ bmbCurr.Bm(),
+ fFirstPage ? pgnoSourceFirst : pgnoNull,
+ fTrue,
+ fUseActiveSpaceRequestReserve ?
+ ( fSPUseActiveReserve | ( fCreateActiveSpaceRequestReserve ? ( fSPContinuous | fSPExactExtent ) : fSPNoFlags ) ) :
+ fSPNoFlags,
+ bmbNext.Pbm() );
+
+ Call( err );
+
+ ( *pcpgMoved )++;
+
+ bmbNext.CopyInto( &bmbCurr );
+ bmbNext.NullifyAndSetPvsToBuffer();
+ }
+
+HandleError:
+ Assert( !Pcsr( pfucb )->FLatched() );
+
+ if ( fActiveSpaceRequestReserveCreated )
+ {
+ DIRResetActiveSpaceRequestReserve( pfucb );
+ }
+
+ bmbCurr.FreeBuffer();
+ bmbNext.FreeBuffer();
+ BTIReleaseMergePaths( pmergePath );
+
+#ifdef DEBUG
+ FMP * const pfmp = PfmpFromIfmp( pfucb->ifmp );
+ if ( pfmp->FExclusiveBySession( pfucb->ppib ) )
+ {
+ Expected( pfmp->FShrinkIsRunning() );
+ Assert( err != JET_errRecordNotFound );
+ Assert( err != errBTShallowTree );
+ if ( err >= JET_errSuccess )
+ {
+ Assert( *pcpgMoved > 0 );
+ Assert( *pcpgMoved == cpgToMove );
+ }
+ }
+#endif
+
+ // Because this function is best effort only, we'll return success if at least one page has been moved.
+ if ( ( err > JET_errSuccess ) || ( ( err < JET_errSuccess ) && ( *pcpgMoved > 0 ) ) )
+ {
+ err = JET_errSuccess;
+ }
+
+ return err;
+}
+
+
// processes one page for merge or empty page operation
// depending on the operation selection in pmergePath->flags
//
diff --git a/dev/ese/src/ese/cat.cxx b/dev/ese/src/ese/cat.cxx
index e8204502..8b63edf1 100644
--- a/dev/ese/src/ese/cat.cxx
+++ b/dev/ese/src/ese/cat.cxx
@@ -6403,7 +6403,6 @@ LOCAL ERR ErrCATIBuildFIELDArray(
{
Assert( JET_errRecordDeleted != err );
Assert( locOnCurBM == pfucbCatalog->locLogical );
- Assert( Pcsr( pfucbCatalog )->FLatched() );
if ( JET_errNoCurrentRecord != err )
return err;
}
@@ -10351,6 +10350,7 @@ ERR ErrCATRenameColumn(
// ================================================================
{
ERR err = JET_errSuccess;
+ BOOL fRollback = fFalse;
const INT cbSzNameNew = (ULONG)strlen( szNameNew ) + 1;
Assert( cbSzNameNew > 1 );
@@ -10366,7 +10366,8 @@ ERR ErrCATRenameColumn(
BOOL fPrimaryIndexPlaceholder = fFalse;
Assert( 0 == ppib->Level() );
- CallR( ErrDIRBeginTransaction( ppib, 34533, NO_GRBIT ) );
+ Call( ErrDIRBeginTransaction( ppib, 34533, NO_GRBIT ) );
+ fRollback = fTrue;
objidTable = pfcbTable->ObjidFDP();
@@ -10389,13 +10390,18 @@ ERR ErrCATRenameColumn(
Call( ErrERRCheck( JET_errColumnNotFound ) );
}
+ if ( FFIELDVersioned( pfield->ffield ) )
+ {
+ Call( ErrERRCheck( JET_errIllegalOperation ) );
+ }
+
pfcbTable->EnterDDL();
// put the new column name in the mempool
// do this before getting the FIELD in case we re-arrange the mempool
err = ptdbTable->MemPool().ErrAddEntry( (BYTE *)szNameNew, cbSzNameNew, &itagColumnNameNew );
- if( err < 0 )
+ if ( err < 0 )
{
pfcbTable->LeaveDDL();
Call( err );
@@ -10461,6 +10467,7 @@ ERR ErrCATRenameColumn(
// once the commit succeeds, no errors can be generated
Call( ErrDIRCommitTransaction( ppib, NO_GRBIT ) );
+ fRollback = fFalse;
pfcbTable->EnterDML();
@@ -10497,14 +10504,14 @@ ERR ErrCATRenameColumn(
HandleError:
- if( 0 != itagColumnNameNew )
+ if ( 0 != itagColumnNameNew )
{
pfcbTable->EnterDDL();
ptdbTable->MemPool().DeleteEntry( itagColumnNameNew );
pfcbTable->LeaveDDL();
}
- if( err < 0 )
+ if ( fRollback )
{
CallSx( ErrDIRRollback( ppib ), JET_errRollbackError );
}
@@ -16631,7 +16638,7 @@ ERR ErrCATIAccumulateIndexLocales(
{
// no entry for this LocaleName + version, add one ...
li.m_cIndices = 1;
- CLocaleNameInfoArray::ERR errArray = parrayLocales->ErrSetEntry( parrayLocales->Size(), li );
+ CLocaleNameInfoArray::ERR errArray = parrayLocales->ErrAppendEntry( li );
if ( CLocaleNameInfoArray::ERR::errSuccess != errArray )
{
Assert( CLocaleNameInfoArray::ERR::errOutOfMemory == errArray );
@@ -16822,16 +16829,16 @@ JETUNITTEST( CATMSysLocales, TestCLocaleInfoArrayWillWorkAsRequiredForMSysLocale
// insert 4 imaginary records
CHECK( 0 == localesarray.Size() );
- err = localesarray.ErrSetEntry( localesarray.Size(), li );
+ err = localesarray.ErrAppendEntry( li );
CHECK( err == CLocaleInfoArray::ERR::errSuccess );
li.m_lcid = 1040;
- err = localesarray.ErrSetEntry( localesarray.Size(), li );
+ err = localesarray.ErrAppendEntry( li );
CHECK( err == CLocaleInfoArray::ERR::errSuccess );
li.m_qwVersion = 0x45;
- err = localesarray.ErrSetEntry( localesarray.Size(), li );
+ err = localesarray.ErrAppendEntry( li );
CHECK( err == CLocaleInfoArray::ERR::errSuccess );
li.m_lcid = 1046;
- err = localesarray.ErrSetEntry( localesarray.Size(), li );
+ err = localesarray.ErrAppendEntry( li );
CHECK( err == CLocaleInfoArray::ERR::errSuccess );
// check that the by offset/iEntry all work to retrieve expected results.
@@ -16895,7 +16902,7 @@ JETUNITTEST( CATMSysLocales, TestCLocaleNameInfoArrayWillWorkAsRequiredForMSysLo
li.m_cIndices = 0x2;
li.m_qwVersion = 0x34;
li.m_sortID = sortID;
- StringCchCopyW( li.m_wszLocaleName, _countof( li.m_wszLocaleName ), L"en-us" );
+ OSStrCbCopyW( li.m_wszLocaleName, sizeof( li.m_wszLocaleName ), L"en-us" );
CLocaleNameInfoArray localesarray;
CLocaleNameInfoArray::ERR err;
@@ -16903,23 +16910,23 @@ JETUNITTEST( CATMSysLocales, TestCLocaleNameInfoArrayWillWorkAsRequiredForMSysLo
// insert 5 imaginary records
CHECK( 0 == localesarray.Size() );
- err = localesarray.ErrSetEntry( localesarray.Size(), li );
+ err = localesarray.ErrAppendEntry( li );
CHECK( err == CLocaleNameInfoArray::ERR::errSuccess );
- StringCchCopyW( li.m_wszLocaleName, _countof( li.m_wszLocaleName ), L"pt-br" );
- err = localesarray.ErrSetEntry( localesarray.Size(), li );
+ OSStrCbCopyW( li.m_wszLocaleName, sizeof( li.m_wszLocaleName ), L"pt-br" );
+ err = localesarray.ErrAppendEntry( li );
CHECK( err == CLocaleNameInfoArray::ERR::errSuccess );
li.m_qwVersion = 0x45;
- err = localesarray.ErrSetEntry( localesarray.Size(), li );
+ err = localesarray.ErrAppendEntry( li );
CHECK( err == CLocaleNameInfoArray::ERR::errSuccess );
- StringCchCopyW( li.m_wszLocaleName, _countof( li.m_wszLocaleName ), L"pt-pt" );
- err = localesarray.ErrSetEntry( localesarray.Size(), li );
+ OSStrCbCopyW( li.m_wszLocaleName, sizeof( li.m_wszLocaleName ), L"pt-pt" );
+ err = localesarray.ErrAppendEntry( li );
CHECK( err == CLocaleNameInfoArray::ERR::errSuccess );
li.m_sortID.Data1++;
- err = localesarray.ErrSetEntry( localesarray.Size(), li );
+ err = localesarray.ErrAppendEntry( li );
CHECK( err == CLocaleNameInfoArray::ERR::errSuccess );
li.m_sortID.Data1--;
@@ -16942,25 +16949,25 @@ JETUNITTEST( CATMSysLocales, TestCLocaleNameInfoArrayWillWorkAsRequiredForMSysLo
// Search for all LocaleName + version combos we inserted ...
ULONG i;
- StringCchCopyW( li.m_wszLocaleName, _countof( li.m_wszLocaleName ), L"pt-br" );
+ OSStrCbCopyW( li.m_wszLocaleName, sizeof( li.m_wszLocaleName ), L"pt-br" );
li.m_qwVersion = 0x34;
i = localesarray.SearchLinear( li, PfnCmpLocaleNameInfo );
CHECK( i == 1 );
- StringCchCopyW( li.m_wszLocaleName, _countof( li.m_wszLocaleName ), L"pt-br" );
+ OSStrCbCopyW( li.m_wszLocaleName, sizeof( li.m_wszLocaleName ), L"pt-br" );
li.m_qwVersion = 0x45;
i = localesarray.SearchLinear( li, PfnCmpLocaleNameInfo );
CHECK( i == 2 );
- StringCchCopyW( li.m_wszLocaleName, _countof( li.m_wszLocaleName ), L"en-us" );
+ OSStrCbCopyW( li.m_wszLocaleName, sizeof( li.m_wszLocaleName ), L"en-us" );
li.m_qwVersion = 0x34;
i = localesarray.SearchLinear( li, PfnCmpLocaleNameInfo );
CHECK( i == 0 );
- StringCchCopyW( li.m_wszLocaleName, _countof( li.m_wszLocaleName ), L"pt-pt" );
+ OSStrCbCopyW( li.m_wszLocaleName, sizeof( li.m_wszLocaleName ), L"pt-pt" );
li.m_qwVersion = 0x45;
i = localesarray.SearchLinear( li, PfnCmpLocaleNameInfo );
@@ -16989,7 +16996,7 @@ JETUNITTEST( CATMSysLocales, TestCLocaleNameInfoArrayWillWorkAsRequiredForMSysLo
it = localesarray.SearchLinear( li, PfnCmpLocaleNameInfo );
CHECK( it == localesarray.iEntryNotFound );
- StringCchCopyW( li.m_wszLocaleName, _countof( li.m_wszLocaleName ), L"st-kg" );
+ OSStrCbCopyW( li.m_wszLocaleName, sizeof( li.m_wszLocaleName ), L"st-kg" );
li.m_qwVersion = 0x34;
it = localesarray.SearchLinear( li, PfnCmpLocaleNameInfo );
@@ -17006,7 +17013,8 @@ INLINE ERR ErrCATIParseLocaleNameInfo(
{
PCWSTR wszCurr;
WCHAR wszSortID[PERSISTED_SORTID_MAX_LENGTH];
- ULONG cchLocaleName;
+ ULONG cbLocaleName;
+ ERR errT; // Not a return value, local only.
Assert( ( NULL != wszLocaleName ) && ( NULL != pqwSortedVersion ) && ( NULL != psortID ) );
@@ -17025,14 +17033,14 @@ INLINE ERR ErrCATIParseLocaleNameInfo(
{
// Empty locale name is valid.
wszCurr++;
- cchLocaleName = 0;
+ cbLocaleName = 0;
}
else
{
wszCurr++;
- cchLocaleName = wcscspn( wszCurr, L"," );
+ cbLocaleName = wcscspn( wszCurr, L"," ) * sizeof(WCHAR);
- if ( ( cchLocaleName == 0 ) || ( cchLocaleName >= NORM_LOCALE_NAME_MAX_LENGTH ) )
+ if ( ( cbLocaleName == 0 ) || ( cbLocaleName >= ( sizeof(WCHAR) * NORM_LOCALE_NAME_MAX_LENGTH ) ) )
{
return ErrERRCheck( JET_errDatabaseCorrupted );
}
@@ -17043,8 +17051,13 @@ INLINE ERR ErrCATIParseLocaleNameInfo(
Assert( 0 == LOSStrCompareW( wszLocaleEntryKey, wszExpectedLocaleName, LOSStrLengthW( wszExpectedLocaleName ) ) );
#endif // DEBUG
- StringCchCopyW( wszLocaleName, cchLocaleName + 1, wszCurr );
- wszLocaleName[cchLocaleName] = L'\0';
+ // Note that we're fibbing about the size of wszLocaleName in order to only
+ // copy a limited number of bytes from wszCurr. What we need is
+ // ErrOSStrCbCopyNW, where we can specify both the size of the destination
+ // buffer as well as the number of bytes to copy.
+ errT = ErrOSStrCbCopyW( wszLocaleName, cbLocaleName + sizeof( WCHAR ), wszCurr );
+ Assert( JET_errSuccess == errT || JET_errBufferTooSmall == errT );
+ wszLocaleName[ cbLocaleName / sizeof( WCHAR ) ] = L'\0';
//
// second, grab the Sort Version out of the key
@@ -17072,17 +17085,19 @@ INLINE ERR ErrCATIParseLocaleNameInfo(
}
wszCurr++;
- ULONG cchSortID = wcscspn( wszCurr, L"," );
+ ULONG cbSortID = sizeof( WCHAR ) * wcscspn( wszCurr, L"," );
C_ASSERT( _countof( wszSortID ) == PERSISTED_SORTID_MAX_LENGTH );
- if ( ( cchSortID == 0 ) || ( cchSortID != PERSISTED_SORTID_MAX_LENGTH - 1 ) )
+ if ( ( cbSortID == 0 ) || ( cbSortID != (sizeof( WCHAR ) * ( PERSISTED_SORTID_MAX_LENGTH - 1 ) ) ) )
{
AssertSz( fFalse, "The sort ID was not of the right size. Should be exactly the size we put in." );
return ErrERRCheck( JET_errDatabaseCorrupted );
}
- StringCchCopyW( wszSortID, cchSortID + 1, wszCurr );
- wszSortID[cchSortID] = L'\0';
+ // Again, fibbing.
+ errT = ErrOSStrCbCopyW( wszSortID, cbSortID + sizeof( WCHAR ), wszCurr );
+ Assert( JET_errSuccess == errT || JET_errBufferTooSmall == errT );
+ wszSortID[ cbSortID / sizeof( WCHAR ) ] = L'\0';
SortIDWsz( wszSortID, psortID );
//
diff --git a/dev/ese/src/ese/checksum_test.cxx b/dev/ese/src/ese/checksum_test.cxx
index c5d17530..41dd3218 100644
--- a/dev/ese/src/ese/checksum_test.cxx
+++ b/dev/ese/src/ese/checksum_test.cxx
@@ -46,9 +46,9 @@ PAGECHECKSUM ComputePageChecksum(
const UINT cb,
const PAGETYPE pagetype,
const ULONG pgno,
- // set fNew to compute new ECC for a page (R/W wrt the large page!!)
- // reset fNew to computer ECC for verification purpose (R/O wrt the page)
- const BOOL fNew = fFalse );
+ // set fWriteChecksum to compute new ECC for a page (R/W wrt the large page!!)
+ // reset fWriteChecksum to computer ECC for verification purpose (R/O wrt the page)
+ const BOOL fWriteChecksum = fFalse );
//
@@ -436,6 +436,7 @@ static void TestSetAndChecksum( unsigned char * const pb )
TestFixOnePage( pb, 8192, databasePage, 129 );
TestFixOnePage( pb, 8192, databasePage, 3097 );
TestFixOnePage( pb, 8192, databasePage, ( 8192 * 8 ) - 1 );
+ TestFixOnePage( pb, 8192, databasePage, IbitNewChecksumFormatFlag( databasePage ) );
// we can't deal with a corruption in the first checksum or the format
// flag. to avoid that, don't corrupt the v1 header at all (the v1 header
@@ -464,6 +465,7 @@ static void TestSetAndChecksum( unsigned char * const pb )
TestFixOnePage( pb, 4096, databasePage, 29000 );
TestFixOnePage( pb, 4096, databasePage, 30009 );
TestFixOnePage( pb, 4096, databasePage, ( 4096 * 8 ) - 1 );
+ TestFixOnePage( pb, 4096, databasePage, IbitNewChecksumFormatFlag( databasePage ) );
// we can't deal with a corruption in the checksum or the format flag. to
// avoid that, don't corrupt the header at all (the header is 40 bytes)
@@ -473,11 +475,8 @@ static void TestSetAndChecksum( unsigned char * const pb )
// single-bit corruptions ECC can't fix
TestFailToFixOnePage( pb, 8192, databasePage, 0 );
- TestFailToFixOnePage( pb, 8192, databasePage, IbitNewChecksumFormatFlag( databasePage ) );
-
TestFailToFixOnePage( pb, 4096, databasePage, 1 );
- TestFailToFixOnePage( pb, 4096, databasePage, IbitNewChecksumFormatFlag( databasePage ) );
-
+
// single-bit corruptions on pages without ECC
TestFailToFixOnePage( pb, 8192, databaseHeader, 100 );
@@ -886,12 +885,10 @@ VOID ExtensiveKnownPageUnitTest( __out_bcount( cbSizeMax ) unsigned char * const
{
cbit++;
- // we currently cannot fix bit flips on the checksum format flag
// we currently cannot fix bit flips on the first block's checksum
const INT fBitBelongsToFirstChecksum = ( ibit / 8 ) < sizeof( XECHECKSUM );
- const INT fBitIsChecksumFormatFlag = ibit == (INT)IbitNewChecksumFormatFlag( databasePage );
- const INT fBitFixableSingleBitError = !( fBitBelongsToFirstChecksum || fBitIsChecksumFormatFlag );
+ const INT fBitFixableSingleBitError = !fBitBelongsToFirstChecksum;
// flip one bit
@@ -971,15 +968,12 @@ VOID ExtensiveKnownPageUnitTest( __out_bcount( cbSizeMax ) unsigned char * const
{
cbit++;
- // we currently cannot fix bit flips on the checksum format flag
// we currently cannot fix bit flips on the first block's checksum
const INT fBit1BelongsToFirstChecksum = ( ibit1 / 8 ) < sizeof( XECHECKSUM );
- const INT fBit1IsChecksumFormatFlag = ibit1 == (INT)IbitNewChecksumFormatFlag( databasePage );
- const INT fBit1FixableSingleBitError = !( fBit1BelongsToFirstChecksum || fBit1IsChecksumFormatFlag );
+ const INT fBit1FixableSingleBitError = !fBit1BelongsToFirstChecksum;
const INT fBit2BelongsToFirstChecksum = ( ibit2 / 8 ) < sizeof( XECHECKSUM );
- const INT fBit2IsChecksumFormatFlag = ibit2 == (INT)IbitNewChecksumFormatFlag( databasePage );
- const INT fBit2FixableSingleBitError = !( fBit2BelongsToFirstChecksum || fBit2IsChecksumFormatFlag );
+ const INT fBit2FixableSingleBitError = !fBit2BelongsToFirstChecksum;
// flip bits
diff --git a/dev/ese/src/ese/cpage.cxx b/dev/ese/src/ese/cpage.cxx
index 3d35281e..f52fae34 100644
--- a/dev/ese/src/ese/cpage.cxx
+++ b/dev/ese/src/ese/cpage.cxx
@@ -44,7 +44,6 @@ i.e Assignment changes ownership -- like the unique_ptr template
*******************************************************************/
#include "std.hxx"
-
#include // required for _alloca()
// We have moved all globals / statics involving g_cbPage out of
@@ -2569,6 +2568,12 @@ ERR CPAGE::ErrLoadPage(
UtilMemCpy( m_bfl.pv, pv, cb );
+ // A loaded page is considered dirty-on-load. So save the scrub state.
+ // For a loaded page, scrub state before dirty isn't available.
+ // So RevertDbtime() will leave the scrub state unchanged.
+ // Note that this is consistent with behavior prior to the bug fix for reverting scrub flag.
+ m_fPageScrubbedPrevSet = fTrue;
+ m_fPageScrubbedPrev = !!FScrubbed();
return JET_errSuccess;
}
@@ -2603,7 +2608,7 @@ VOID CPAGE::LoadNewPage(
#ifdef ENABLE_JET_UNIT_TEST
// ================================================================
-VOID CPAGE::LoadNewTestPage( _In_ const ULONG cb, _In_ const IFMP ifmp )
+VOID CPAGE::LoadNewTestPage( _In_ const ULONG cb, _In_ const IFMP ifmp, const PGNO pgno /* = 42 */ )
// ================================================================
{
Assert( 0 != cb );
@@ -2626,7 +2631,7 @@ VOID CPAGE::LoadNewTestPage( _In_ const ULONG cb, _In_ const IFMP ifmp )
// Initialize the Page so it is usable for testing
//
- PreInitializeNewPage_( ppibNil, ifmp, 2, 3, 0 );
+ PreInitializeNewPage_( ppibNil, ifmp, pgno, 3, 0 );
ConsumePreInitPage( 0x0 );
// Avoid Uninitialized Page issues
@@ -2980,6 +2985,7 @@ VOID CPAGE::RevertDbtime( const DBTIME dbtime, const ULONG fFlags )
Expected( fFlags != 0 );
m_platchManager->AssertPageIsDirty( m_bfl );
Assert( FAssertWriteLatch( ) );
+ Assert( m_fPageScrubbedPrevSet ); // prev fPageScrubbed state must've been captured on dirty.
((PGHDR*)m_bfl.pv)->dbtimeDirtied = dbtime;
@@ -2987,33 +2993,23 @@ VOID CPAGE::RevertDbtime( const DBTIME dbtime, const ULONG fFlags )
// state with the way scrubbed was implemented embedded in ::Dirty() and ::DirtyForScrub().
// Still, we don't expect any other flags to change other than fPageScrubbed.
//
- // Its also possible we are replaying a log on an available lag on a table which was deleted and reverted with fPageFDPDelete.
- // We do not want to overwrite that flag. So we might be restoring that flag.
- //
// If the FireWall() below goes off, it doesn't necessarily mean we have
// a corruption problem, but it means there will be a divergence between
// copies in a replicated system that may triger a DB divergence error.
#ifndef ENABLE_JET_UNIT_TEST
- if ( ( FFlags() | fPageScrubbed ) != ( fFlags | fPageScrubbed ) &&
- ( FFlags() | fPageFDPDelete ) != ( fFlags | fPageFDPDelete ) &&
- ( FFlags() | fPageScrubbed | fPageFDPDelete ) != ( fFlags | fPageScrubbed | fPageFDPDelete ) )
+ if ( ( FFlags() | fPageScrubbed ) != ( fFlags | fPageScrubbed ) )
{
FireWall( OSFormat( "RevertDbtime:0x%I32x:0x%I32x", fFlags, FFlags() ) );
}
-#endif
- const BOOL fScrubbedBefore = ( fFlags & fPageScrubbed );
- if ( !FScrubbed() != !fScrubbedBefore )
- {
- SetFScrubbedValue_( fScrubbedBefore );
- }
- // If existing root page had been marked for FDP delete but current root page isn't, mark it again.
- const BOOL fPageFDPDeleteBefore = ( fFlags & fPageFDPDelete );
- if ( fPageFDPDeleteBefore && !FPageFDPDelete() )
+ const ULONG fScrubbedBefore = ( fFlags & fPageScrubbed );
+ if ( m_fPageScrubbedPrev != fScrubbedBefore )
{
- Assert( FRootPage() );
- SetPageFDPDelete( fPageFDPDeleteBefore );
+ FireWall( OSFormat( "RevertDbtime(fPageScrubbed):0x%I32x:0x%I32x", fScrubbedBefore, m_fPageScrubbedPrev ) );
}
+#endif
+
+ SetFScrubbedValue_( m_fPageScrubbedPrev );
}
@@ -3388,6 +3384,35 @@ VOID CPAGE::ReplaceReservedTag( INT itag, const DATA* rgdata, INT cdata )
Replace_( itag, rgdata, cdata, 0 );
}
+// ================================================================
+VOID CPAGE::ResetReservedTag( INT itag, INT cb, BYTE fill )
+// ================================================================
+//
+// Sets size and pattern-fills a reserved tag.
+//
+//-
+{
+ Assert( itag < CTagReserved_() );
+
+ const BOOL fSmallFormat = FSmallPageFormat();
+ PGHDR* ppghdr = (PGHDR*) m_bfl.pv;
+ TAG* ptag = PtagFromItag_( itag );
+
+ // Release space. Stored data will be lost !
+ ppghdr->ibMicFree += ptag->Cb( fSmallFormat );
+ ptag->SetIb( this, 0 );
+ ptag->SetCb( this, 0 );
+ FreeSpace_( cb );
+
+ ptag->SetIb( this, ppghdr->ibMicFree );
+ ppghdr->ibMicFree = USHORT( ppghdr->ibMicFree + cb );
+ ptag->SetCb( this, (USHORT) cb );
+ const USHORT cbFree = (USHORT) ( ppghdr->cbFree - cb );
+ ppghdr->cbFree = cbFree;
+
+ BYTE* pb = PbFromIb_( ptag->Ib( fSmallFormat ) );
+ memset( pb, fill, ptag->Cb( fSmallFormat ) );
+}
// ================================================================
bool CPAGE::FResvTagFormatEnabled()
@@ -3430,6 +3455,8 @@ VOID CPAGE::ReleaseWriteLatch( BOOL fTossImmediate )
m_objidPreInit = objidNil;
}
+ m_fPageScrubbedPrevSet = fFalse;
+
m_platchManager->ReleaseWriteLatch( &m_bfl, !!fTossImmediate );
Abandon_();
Assert( FAssertUnused_( ) );
@@ -3447,6 +3474,7 @@ VOID CPAGE::ReleaseRDWLatch( BOOL fTossImmediate )
ASSERT_VALID( this );
DebugCheckAll();
+ m_fPageScrubbedPrevSet = fFalse;
m_platchManager->ReleaseRDWLatch( &m_bfl, !!fTossImmediate );
Abandon_();
Assert( FAssertUnused_( ) );
@@ -3467,6 +3495,7 @@ VOID CPAGE::ReleaseReadLatch( BOOL fTossImmediate )
DebugCheckAll();
#endif // DEBUG_PAGE
+ m_fPageScrubbedPrevSet = fFalse;
m_platchManager->ReleaseReadLatch( &m_bfl, !!fTossImmediate );
Abandon_();
Assert( FAssertUnused_( ) );
@@ -3809,6 +3838,12 @@ VOID CPAGE::Dirty_( const BFDirtyFlags bfdf )
// for now, but someday in the future we may allow dirty small pages
Assert( FIsNormalSized() );
+ if ( !m_fPageScrubbedPrevSet )
+ {
+ m_fPageScrubbedPrevSet = fTrue;
+ m_fPageScrubbedPrev = !!FScrubbed();
+ }
+
if( FLoadedPage() )
{
}
@@ -4721,7 +4756,7 @@ ERR CPAGE::ErrCheckPage(
const ULONG_PTR pbPageDataEnd = PbDataEnd_(); // m_bfl.pv + CbBuffer() - tag array size (off itagMicFree)
if ( pbPageDataEnd <= ( pbPageDataStart + 1 /* generous 1 byte in data section, tighter check next */ ) )
{
- MakeCorruptionDetailsSz( L"itagMicFree / tag array too large, overlapping PGHDR (%p,%p,%I64d / %d)", pbPageDataEnd, pbPageDataStart, ctags, CbTagArray_() );
+ MakeCorruptionDetailsSz( L"itagMicFree / tag array too large, overlapping PGHDR (%p,%p,%I64d / %d)", (PVOID)pbPageDataEnd, (PVOID)pbPageDataStart, ctags, CbTagArray_() );
(*pcprintf)( "%ws\r\n", wszCorruptionDetails );
Error( ErrCaptureCorruptedPageInfoSz( mode, L"TagArrayWalkingOntoPghdr", wszCorruptionDetails, fLogEvent ) );
}
@@ -4913,35 +4948,26 @@ ERR CPAGE::ErrCheckPage(
// The whole line is starting above the data start, i.e. off the data section, and possibly even off page.
MakeCorruptionDetailsSz( L"TAG %d computed offset starts too high (ib=%d, cb=%d, %p > %p)", itag, ib, cb, line.pv, pbPageDataEnd );
(*pcprintf)( "%ws\r\n", wszCorruptionDetails );
- PageAssertTrack( *this, fFalse, "LineEntirelyAboveDataSection" );
-#ifdef DEBUG
Error( ErrCaptureCorruptedPageInfoSz( mode, L"LineEntirelyAboveDataSection", wszCorruptionDetails, fLogEvent ) );
-#endif
}
if ( pbLineLastByte > pbPageDataEnd )
{
// The line ends above the data start, i.e. off the data section, but does start / overlaping in valid data section.
MakeCorruptionDetailsSz( L"TAG %d computed offset starts too high (ib=%d, cb=%d, %p > %p)", itag, ib, cb, pbLineLastByte, pbPageDataEnd );
(*pcprintf)( "%ws\r\n", wszCorruptionDetails );
- PageAssertTrack( *this, FNegTest( fCorruptingPageLogically ), "LineEndsAboveDataSection" );
-#ifdef DEBUG
Error( ErrCaptureCorruptedPageInfoSz( mode, L"LineEndsAboveDataSection", wszCorruptionDetails, fLogEvent ) );
-#endif
}
if ( errGetLine < JET_errSuccess || !FOnData( line.pv, line.cb ) )
{
// catch all
- CHAR szGetLineErr[40];
- OSStrCbFormatA( szGetLineErr, sizeof( szGetLineErr ), "GetLineFailed:%d\n", errGetLine );
+ WCHAR wszGetLineErr[40];
+ OSStrCbFormatW( wszGetLineErr, sizeof( wszGetLineErr ), L"GetLineFailed:%d\n", errGetLine );
MakeCorruptionDetailsSz( L"GetLineFailed:%d\n", errGetLine );
MakeCorruptionDetailsSz( L"UNCAUGHT: TAG %d ErrGetPtr() failed or got line off page (ib=%d, cb=%d, err=%d,f=%d).", itag, ib, cb, errGetLine, FOnData( line.pv, line.cb ) );
(*pcprintf)( "%ws\r\n", wszCorruptionDetails );
// there should not be too many errors coming from ErrGetLine() that we can't embed the err in the corruption type.
- PageAssertTrack( *this, FNegTest( fCorruptingPageLogically ), "GetLineFailed:%d\n", errGetLine );
-#ifdef DEBUG
- Error( ErrCaptureCorruptedPageInfoSz( mode, szGetLineErr, wszCorruptionDetails, fLogEvent ) );
-#endif
+ Error( ErrCaptureCorruptedPageInfoSz( mode, wszGetLineErr, wszCorruptionDetails, fLogEvent ) );
}
// do some simple KEYDATAFLAGS checks
@@ -5040,12 +5066,12 @@ ERR CPAGE::ErrCheckPage(
if ( errGetKdf < JET_errSuccess )
{
- CHAR szGetKdfErr [40];
+ WCHAR wszGetKdfErr [40];
// there should not be too many errors coming from ErrNDIGetKeydataflags() that we can't embed the err in the corruption type.
- OSStrCbFormatA( szGetKdfErr, sizeof( szGetKdfErr ), "NdiGetKdfFailed:%d", errGetKdf );
- MakeCorruptionDetailsSz( L"TAG %d failed to load NDIGetKeydataFlags with %d\r\n", errGetKdf );
+ OSStrCbFormatW( wszGetKdfErr, sizeof( wszGetKdfErr ), L"NdiGetKdfFailed:%d", errGetKdf );
+ MakeCorruptionDetailsSz( L"TAG %d failed to load NDIGetKeydataFlags with %d\r\n", itag, errGetKdf );
(*pcprintf)( "%ws\r\n", wszCorruptionDetails );
- Error( ErrCaptureCorruptedPageInfoSz( mode, L"TagDataTooLarge", wszCorruptionDetails, fLogEvent ) );
+ Error( ErrCaptureCorruptedPageInfoSz( mode, wszGetKdfErr, wszCorruptionDetails, fLogEvent ) );
}
if ( grbitExtensiveCheck & CheckLinesInOrder )
@@ -5765,7 +5791,7 @@ VOID CPAGE::DehydratePageUnadjusted_( _In_ const ULONG cbNewSize )
Enforce( cbShrinkage < CbPage() );
Enforce( cbShrinkage < 0x10000 );
- Enforce( ppghdr->cbFree >= cbShrinkage );
+ PageEnforce( (*this), ppghdr->cbFree >= cbShrinkage );
Enforce( ppghdr->ibMicFree < ( m_platchManager->CbBuffer( m_bfl ) - cbShrinkage ) );
Assert( ppghdr->ibMicFree < m_platchManager->CbBuffer( m_bfl ) - CbTagArray_() );
@@ -6507,7 +6533,7 @@ ERR ErrAccumulatePageStats(
// ================================================================
-VOID CPAGE::DumpAllocMap_( _TCHAR * rgchBuf, CPRINTF * pcprintf ) const
+VOID CPAGE::DumpAllocMap_( CHAR * rgchBuf, CPRINTF * pcprintf ) const
// ================================================================
//
// Prints a 'map' of the page, showing how it is used.
@@ -6530,7 +6556,7 @@ VOID CPAGE::DumpAllocMap_( _TCHAR * rgchBuf, CPRINTF * pcprintf ) const
// header
for ( ich = 0; ich < CbPageHeader(); ++ich )
{
- rgchBuf[ich+ichBase] = _T( 'H' );
+ rgchBuf[ich+ichBase] = 'H';
}
ichBase = ich;
@@ -6543,7 +6569,7 @@ VOID CPAGE::DumpAllocMap_( _TCHAR * rgchBuf, CPRINTF * pcprintf ) const
Assert( ptag->Ib( FSmallPageFormat() ) < min( CbPage(), m_platchManager->CbBuffer( m_bfl ) ) );
for ( ich = ptag->Ib( FSmallPageFormat() ); ich < (ptag->Cb( FSmallPageFormat() ) + ptag->Ib( FSmallPageFormat() )); ++ich )
{
- rgchBuf[ich+ichBase] = _T( 'E' );
+ rgchBuf[ich+ichBase] = 'E';
}
for ( itag = 1; itag < ITagMicFree_(); ++itag )
@@ -6573,7 +6599,7 @@ VOID CPAGE::DumpAllocMap_( _TCHAR * rgchBuf, CPRINTF * pcprintf ) const
ich = ptagT->Ib( FSmallPageFormat() );
for ( ; ich < ((ptagT->Cb( FSmallPageFormat() )) + (ptagT->Ib( FSmallPageFormat() ))); ++ich )
{
- rgchBuf[ich+ichBase] = ( iptag % 2 ) ? _T( '%' ) : _T( '#' );
+ rgchBuf[ich+ichBase] = ( iptag % 2 ) ? '%' : '#';
}
}
@@ -6583,19 +6609,19 @@ VOID CPAGE::DumpAllocMap_( _TCHAR * rgchBuf, CPRINTF * pcprintf ) const
for ( ich = 0; ich < (INT) ( sizeof( CPAGE::TAG ) * ITagMicFree_() ); ++ich )
{
- rgchBuf[ich+ichBase] = _T( 'T' );
+ rgchBuf[ich+ichBase] = 'T';
}
// print the map
for ( INT iRow = 0; iRow < (INT)m_platchManager->CbBuffer( m_bfl )/cchDumpAllocRow; ++iRow )
{
- _TCHAR rgchLineBuf[cchDumpAllocRow+1+1];
- UtilMemCpy( rgchLineBuf, &(rgchBuf[iRow*cchDumpAllocRow]), cchDumpAllocRow * sizeof( _TCHAR ) );
- rgchLineBuf[cchDumpAllocRow] = _T( '\n' );
+ CHAR rgchLineBuf[cchDumpAllocRow+1+1];
+ UtilMemCpy( rgchLineBuf, &(rgchBuf[iRow*cchDumpAllocRow]), cchDumpAllocRow * sizeof( CHAR ) );
+ rgchLineBuf[cchDumpAllocRow] = '\n';
rgchLineBuf[cchDumpAllocRow+1] = 0;
(*pcprintf)( "%s", rgchLineBuf );
}
- (*pcprintf)( _T( "\n" ) );
+ (*pcprintf)( "\n" );
}
// ================================================================
@@ -6603,12 +6629,12 @@ ERR CPAGE::DumpAllocMap( CPRINTF * pcprintf ) const
// ================================================================
{
const INT cchBuf = CbPage();
- _TCHAR rgchBuf[g_cbPageMax];
+ CHAR rgchBuf[g_cbPageMax];
for ( INT ich = 0; ich < cchBuf && ich < (sizeof(rgchBuf)/sizeof(rgchBuf[0])); ++ich )
{
// we have to use a loop, not memset, so this will work with unicode
- rgchBuf[ich] = _T( '.' );
+ rgchBuf[ich] = '.';
}
#pragma prefast( pop )
@@ -6640,7 +6666,7 @@ ERR CPAGE::DumpTags( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
if ( ErrEnumTags( ErrAccumulatePageStats, (void*)&btsPageSpace ) < JET_errSuccess )
{
- (*pcprintf)( _T( "Failed to accumulate page stats!\n" ) );
+ (*pcprintf)( "Failed to accumulate page stats!\n" );
}
for ( INT itag = 0; itag < ITagMicFree_(); ++itag )
@@ -6663,7 +6689,7 @@ ERR CPAGE::DumpTags( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
{
if ( itag < CTagReserved_() )
{
- (*pcprintf)( _T( "TAG %3d: cb:0x%04x,ib:0x%04x offset:0x%04x-0x%04x flags:0x%04x %s" ),
+ (*pcprintf)( "TAG %3d: cb:0x%04x,ib:0x%04x offset:0x%04x-0x%04x flags:0x%04x %s",
itag,
ptag->Cb( FSmallPageFormat() ),
ptag->Ib( FSmallPageFormat() ),
@@ -6684,7 +6710,7 @@ ERR CPAGE::DumpTags( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
if( ErrSPREPAIRValidateSpaceNode( &kdf, &pgnoLast, &cpgExtent, &cwszPoolName ) >= JET_errSuccess )
{
(*pcprintf)(
- _T( "TAG %3d: cb=0x%04x,ib=0x%04x SP: %ws: %d,%d-%d flags=0x%04x %s" ),
+ "TAG %3d: cb=0x%04x,ib=0x%04x SP: %ws: %d,%d-%d flags=0x%04x %s",
itag,
ptag->Cb( FSmallPageFormat() ),
ptag->Ib( FSmallPageFormat() ),
@@ -6700,7 +6726,7 @@ ERR CPAGE::DumpTags( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
if ( !fHandledSpecialCase )
{
- (*pcprintf)( _T( "TAG %3d: cb:0x%04x,ib:0x%04x prefix:cb=0x%04x suffix:cb=0x%04x data:cb=0x%04x offset:0x%04x-0x%04x flags:0x%04x %s" ),
+ (*pcprintf)( "TAG %3d: cb:0x%04x,ib:0x%04x prefix:cb=0x%04x suffix:cb=0x%04x data:cb=0x%04x offset:0x%04x-0x%04x flags:0x%04x %s",
itag,
ptag->Cb( FSmallPageFormat() ),
ptag->Ib( FSmallPageFormat() ),
@@ -6721,7 +6747,7 @@ ERR CPAGE::DumpTags( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
if ( itag < CTagReserved_() )
{
(*pcprintf)(
- _T( "TAG %3d: pb=0x%I64x,cb=0x%04x,ib=0x%04x flags=0x%04x %s" ),
+ "TAG %3d: pb=0x%I64x,cb=0x%04x,ib=0x%04x flags=0x%04x %s",
itag,
__int64( dwAddress ),
ptag->Cb( FSmallPageFormat() ),
@@ -6741,7 +6767,7 @@ ERR CPAGE::DumpTags( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
if( ErrSPREPAIRValidateSpaceNode( &kdf, &pgnoLast, &cpgExtent, &wsczPoolName ) >= JET_errSuccess )
{
(*pcprintf)(
- _T( "TAG %3d: pb=0x%I64x,cb=0x%04x,ib=0x%04x SP: %ws: %d,%d-%d flags=0x%04x %s" ),
+ "TAG %3d: pb=0x%I64x,cb=0x%04x,ib=0x%04x SP: %ws: %d,%d-%d flags=0x%04x %s",
itag,
__int64( dwAddress ),
ptag->Cb( FSmallPageFormat() ),
@@ -6760,7 +6786,7 @@ ERR CPAGE::DumpTags( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
{
// If nothing could recognize and handle the special case, then print out a regular line.
(*pcprintf)(
- _T( "TAG %3d: pb=0x%I64x,cb=0x%04x,ib=0x%04x prefix:cb=0x%04x suffix:pb=0x%I64x,cb=0x%04x data:pb=0x%I64x,cb=0x%04x flags=0x%04x %s" ),
+ "TAG %3d: pb=0x%I64x,cb=0x%04x,ib=0x%04x prefix:cb=0x%04x suffix:pb=0x%I64x,cb=0x%04x data:pb=0x%I64x,cb=0x%04x flags=0x%04x %s",
itag,
__int64( dwAddress ),
ptag->Cb( FSmallPageFormat() ),
@@ -6793,44 +6819,44 @@ ERR CPAGE::DumpTags( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
if ( 0 == ITagMicFree_() )
{
- (*pcprintf)( _T( "[No tags found]\n" ) );
+ (*pcprintf)( "[No tags found]\n" );
}
else
{
- (*pcprintf)( _T( "\n" ) );
+ (*pcprintf)( "\n" );
if ( CStatsFromPv(btsPageSpace.phistoNodeCounts)->C() )
{
Assert( CStatsFromPv( btsPageSpace.phistoNodeCounts )->C() == CTagReserved_() );
Assert( CStatsFromPv(btsPageSpace.phistoNodeCounts)->Min() == CStatsFromPv(btsPageSpace.phistoNodeCounts)->Ave() );
Assert( CStatsFromPv(btsPageSpace.phistoNodeCounts)->Max() == CStatsFromPv(btsPageSpace.phistoNodeCounts)->Ave() );
- (*pcprintf)( _T( "Nodes: %I64d\n" ),
+ (*pcprintf)( "Nodes: %I64d\n",
CStatsFromPv(btsPageSpace.phistoNodeCounts)->Ave(),
CStatsFromPv(btsPageSpace.phistoKeyCompression)->C(),
CStatsFromPv(btsPageSpace.phistoUnreclaimedBytes)->C() );
- (*pcprintf)( _T( " min, ave, max, total\n" ) );
- (*pcprintf)( _T( " Logical Key Sizes: %5I64d, %6.1f, %5I64d, %5I64d\n" ),
+ (*pcprintf)( " min, ave, max, total\n" );
+ (*pcprintf)( " Logical Key Sizes: %5I64d, %6.1f, %5I64d, %5I64d\n",
CStatsFromPv(btsPageSpace.phistoKeySizes)->Min(),
CStatsFromPv(btsPageSpace.phistoKeySizes)->DblAve(),
CStatsFromPv(btsPageSpace.phistoKeySizes)->Max(),
CStatsFromPv(btsPageSpace.phistoKeySizes)->Total() );
if ( CStatsFromPv(btsPageSpace.phistoKeyCompression)->C() )
{
- (*pcprintf)( _T( " Key Compression: %5I64d, %6.1f, %5I64d, %5I64d (nodes=%I64d)\n" ),
+ (*pcprintf)( " Key Compression: %5I64d, %6.1f, %5I64d, %5I64d (nodes=%I64d)\n",
CStatsFromPv(btsPageSpace.phistoKeyCompression)->Min(),
CStatsFromPv(btsPageSpace.phistoKeyCompression)->DblAve(),
CStatsFromPv(btsPageSpace.phistoKeyCompression)->Max(),
CStatsFromPv(btsPageSpace.phistoKeyCompression)->Total(),
CStatsFromPv(btsPageSpace.phistoKeyCompression)->C() );
}
- (*pcprintf)( _T( " Node Data Sizes: %5I64d, %6.1f, %5I64d, %5I64d\n" ),
+ (*pcprintf)( " Node Data Sizes: %5I64d, %6.1f, %5I64d, %5I64d\n",
CStatsFromPv(btsPageSpace.phistoDataSizes)->Min(),
CStatsFromPv(btsPageSpace.phistoDataSizes)->DblAve(),
CStatsFromPv(btsPageSpace.phistoDataSizes)->Max(),
CStatsFromPv(btsPageSpace.phistoDataSizes)->Total() );
if ( CStatsFromPv(btsPageSpace.phistoUnreclaimedBytes)->C() )
{
- (*pcprintf)( _T( " Unreclaimed Space: %5I64d, %6.1f, %5I64d, %5I64d (nodes=%I64d)\n" ),
+ (*pcprintf)( " Unreclaimed Space: %5I64d, %6.1f, %5I64d, %5I64d (nodes=%I64d)\n",
CStatsFromPv(btsPageSpace.phistoUnreclaimedBytes)->Min(),
CStatsFromPv(btsPageSpace.phistoUnreclaimedBytes)->DblAve(),
CStatsFromPv(btsPageSpace.phistoUnreclaimedBytes)->Max(),
@@ -6840,12 +6866,12 @@ ERR CPAGE::DumpTags( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
}
else
{
- (*pcprintf)( _T( " No nodes, except maybe external header. No stats.\n" ) );
+ (*pcprintf)( " No nodes, except maybe external header. No stats.\n" );
}
}
- (*pcprintf)( _T( "\n" ) );
+ (*pcprintf)( "\n" );
return 0;
}
@@ -6871,7 +6897,7 @@ VOID CPAGE::DumpTag( CPRINTF * pcprintf, const INT iline, const DWORD_PTR dwOffs
ptag->FFlags( this, FSmallPageFormat() ) & fNDCompressed ? 'c' : ' ' );
(*pcprintf)(
- _T( "TAG %d: pb=0x%I64x,cb=0x%04x,ib=0x%04x prefix:cb=0x%04x suffix:pb=0x%I64x,cb=0x%04x data:pb=0x%I64x,cb=0x%04x flags=0x%04x %s\n" ),
+ "TAG %d: pb=0x%I64x,cb=0x%04x,ib=0x%04x prefix:cb=0x%04x suffix:pb=0x%I64x,cb=0x%04x data:pb=0x%I64x,cb=0x%04x flags=0x%04x %s\n",
itag,
__int64( PbFromIb_( 0 ) + ptag->Ib( FSmallPageFormat() ) + dwOffset ),
ptag->Cb( FSmallPageFormat() ),
@@ -6904,7 +6930,7 @@ ERR CPAGE::DumpHeader( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
DumpPageChecksumInfo( m_bfl.pv, m_platchManager->CbBuffer( m_bfl ), databasePage, m_pgno, pcprintf );
const __int64 chksumLogPage = LoggedDataChecksum().rgChecksum[0];
(*pcprintf)( " logged data checksum = %16I64x\n", chksumLogPage );
- (*pcprintf)( _T( "\n" ) );
+ (*pcprintf)( "\n" );
(*pcprintf)( FORMAT_INT( CPAGE::PGHDR, (PGHDR*)m_bfl.pv, checksum, dwOffset ) );
(*pcprintf)( FORMAT_UINT( CPAGE::PGHDR, (PGHDR*)m_bfl.pv, dbtimeDirtied, dwOffset ) );
@@ -6929,29 +6955,34 @@ ERR CPAGE::DumpHeader( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
if( FLeafPage() )
{
- (*pcprintf)( _T( "\t\tLeaf page\n" ) );
+ (*pcprintf)( "\t\tLeaf page\n" );
}
if( FParentOfLeaf() )
{
- (*pcprintf)( _T( "\t\tParent of leaf\n" ) );
+ (*pcprintf)( "\t\tParent of leaf\n" );
}
if( FInvisibleSons() )
{
- (*pcprintf)( _T( "\t\tInternal page\n" ) );
+ (*pcprintf)( "\t\tInternal page\n" );
}
if( FRootPage() )
{
- (*pcprintf)( _T( "\t\tRoot page\n" ) );
+ (*pcprintf)( "\t\tRoot page\n" );
+ }
+
+ if ( FBBTBuffPage() )
+ {
+ (*pcprintf)( "\t\tBBT %sPage", FBBTBuffRootPage() ? "Base " : "" );
}
BOOL fNewExtHdrFormat = fFalse;
BYTE fNodeFlag = 0;
if( FFDPPage() )
{
- (*pcprintf)( _T( "\t\tFDP page\n" ) );
+ (*pcprintf)( "\t\tFDP page\n" );
const TAG * const ptag = PtagFromItag_( 0 );
@@ -6964,7 +6995,7 @@ ERR CPAGE::DumpHeader( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
|| ptag->Ib( FSmallPageFormat() ) < 0
|| ptag->Ib( FSmallPageFormat() ) > m_platchManager->CbBuffer( m_bfl ) - CbPageHeader() - sizeof(TAG) )
{
- (*pcprintf)( _T( "\t\tCorrupted External Header\n" ) );
+ (*pcprintf)( "\t\tCorrupted External Header\n" );
}
else
{
@@ -6978,14 +7009,14 @@ ERR CPAGE::DumpHeader( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
fNodeFlag = *pb;
++pb;
- (*pcprintf)( _T( "\t\tNew external header format\n" ) );
+ (*pcprintf)( "\t\tNew external header format\n" );
if ( fNodeFlag & BNDIGetPersistedNrfFlag( noderfSpaceHeader ) )
{
- (*pcprintf)( _T( "\t\t\tSpace header flag presents\n" ) );
+ (*pcprintf)( "\t\t\tSpace header flag presents\n" );
}
if ( fNodeFlag & BNDIGetPersistedNrfFlag( noderfIsamAutoInc ) )
{
- (*pcprintf)( _T( "\t\t\tAutoInc flag presents\n" ) );
+ (*pcprintf)( "\t\t\tAutoInc flag presents\n" );
}
const USHORT usTagSize = ptag->Cb( FSmallPageFormat() );
@@ -7002,7 +7033,7 @@ ERR CPAGE::DumpHeader( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
// check the expected tag size is consistent with the flag
if ( usExpectedTagSize != usTagSize )
{
- (*pcprintf)( _T( "\t\tCorrupted Extended External Header. External header flag %d, Expected external header size %d, actual size %d.\n" ),
+ (*pcprintf)( "\t\tCorrupted Extended External Header. External header flag %d, Expected external header size %d, actual size %d.\n",
fNodeFlag,
usExpectedTagSize,
usTagSize );
@@ -7016,7 +7047,7 @@ ERR CPAGE::DumpHeader( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
}
else
{
- (*pcprintf)( _T( "Corruption, on a FDP page with no space header!" ) );
+ (*pcprintf)( "Corruption, on a FDP page with no space header!" );
AssertSz( fFalse, "Corruption, on an FDP page with no space header!" );
}
@@ -7036,35 +7067,35 @@ ERR CPAGE::DumpHeader( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
if ( psph->FMultipleExtent() )
{
(*pcprintf)(
- _T( "\t\t\tMultiple Extent Space (ParentFDP: %d, pgnoOE: %d)\n" ),
+ "\t\t\tMultiple Extent Space (ParentFDP: %d, pgnoOE: %d)\n",
psph->PgnoParent(),
psph->PgnoOE() );
}
else
{
- (*pcprintf)( _T( "\t\t\tSingle Extent Space (ParentFDP: %d, CpgPri: %d, AvailBitmap: 0x%08X)\n" ), psph->PgnoParent(), psph->CpgPrimary(), psph->RgbitAvail() );
+ (*pcprintf)( "\t\t\tSingle Extent Space (ParentFDP: %d, CpgPri: %d, AvailBitmap: 0x%08X)\n", psph->PgnoParent(), psph->CpgPrimary(), psph->RgbitAvail() );
}
}
if ( fNeedPrintAutoInc )
{
- (*pcprintf)( _T( "\t\t\tAuto increment maximum: %d\n" ), qwAutoInc );
+ (*pcprintf)( "\t\t\tAuto increment maximum: %d\n", qwAutoInc );
}
}
}
if( FEmptyPage() )
{
- (*pcprintf)( _T( "\t\tEmpty page\n" ) );
+ (*pcprintf)( "\t\tEmpty page\n" );
}
if( FPreInitPage() )
{
- (*pcprintf)( _T( "\t\tPre-init page\n" ) );
+ (*pcprintf)( "\t\tPre-init page\n" );
}
if( FSpaceTree() )
{
- (*pcprintf)( _T( "\t\tSpace tree page" ) );
+ (*pcprintf)( "\t\tSpace tree page" );
if ( FRootPage() )
{
@@ -7073,7 +7104,7 @@ ERR CPAGE::DumpHeader( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
|| ptag->Ib( FSmallPageFormat() ) < 0
|| ptag->Ib( FSmallPageFormat() ) > m_platchManager->CbBuffer( m_bfl ) - CbPageHeader() - sizeof(TAG) )
{
- (*pcprintf)( _T( "\tCorrupted Split Buffer!\n" ) );
+ (*pcprintf)( "\tCorrupted Split Buffer!\n" );
}
else
{
@@ -7082,56 +7113,56 @@ ERR CPAGE::DumpHeader( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
0 == pslitbuf->CpgBuffer2() )
{
- (*pcprintf)( _T( " (spbuf: none)\n" ) );
+ (*pcprintf)( " (spbuf: none)\n" );
}
else
{
- (*pcprintf)( _T( " (spbuf:" ) );
+ (*pcprintf)( " (spbuf:" );
if ( pslitbuf->CpgBuffer1() )
{
- (*pcprintf)( _T( " buf1: %d-%d (%d)" ),
+ (*pcprintf)( " buf1: %d-%d (%d)",
pslitbuf->PgnoLastBuffer1() - pslitbuf->CpgBuffer1() + 1,
pslitbuf->PgnoLastBuffer1(), pslitbuf->CpgBuffer1() );
}
if ( pslitbuf->CpgBuffer2() )
{
- (*pcprintf)( _T( " buf2: %d-%d (%d)" ),
+ (*pcprintf)( " buf2: %d-%d (%d)",
pslitbuf->PgnoLastBuffer2() - pslitbuf->CpgBuffer2() + 1,
pslitbuf->PgnoLastBuffer2(), pslitbuf->CpgBuffer2() );
}
- (*pcprintf)( _T( ") \n" ) );
+ (*pcprintf)( ") \n" );
}
}
}
else
{
- (*pcprintf)( _T( "\n" ) );
+ (*pcprintf)( "\n" );
}
}
if( FRepairedPage() )
{
- (*pcprintf)( _T( "\t\tRepaired page\n" ) );
+ (*pcprintf)( "\t\tRepaired page\n" );
}
if( FPrimaryPage() )
{
- (*pcprintf)( _T( "\t\tPrimary page\n" ) );
+ (*pcprintf)( "\t\tPrimary page\n" );
Assert( !FIndexPage() );
}
if( FIndexPage() )
{
- (*pcprintf)( _T( "\t\tIndex page " ) );
+ (*pcprintf)( "\t\tIndex page " );
if ( FNonUniqueKeys() )
{
- (*pcprintf)( _T( "(non-unique keys)\n" ) );
+ (*pcprintf)( "(non-unique keys)\n" );
}
else
{
- (*pcprintf)( _T( "(unique keys)\n" ) );
+ (*pcprintf)( "(unique keys)\n" );
}
}
else
@@ -7141,36 +7172,36 @@ ERR CPAGE::DumpHeader( CPRINTF * pcprintf, DWORD_PTR dwOffset ) const
if( FLongValuePage() )
{
- (*pcprintf)( _T( "\t\tLong Value page\n" ) );
+ (*pcprintf)( "\t\tLong Value page\n" );
}
if( FNewRecordFormat() )
{
- (*pcprintf)( _T( "\t\tNew record format\n" ) );
+ (*pcprintf)( "\t\tNew record format\n" );
}
if( FNewChecksumFormat() )
{
- (*pcprintf)( _T( "\t\tNew checksum format\n" ) );
+ (*pcprintf)( "\t\tNew checksum format\n" );
}
if( FScrubbed() )
{
- (*pcprintf)( _T( "\t\tScrubbed\n" ) );
+ (*pcprintf)( "\t\tScrubbed\n" );
}
if ( FPageFDPRootDelete() )
{
- (*pcprintf)( _T( "\t\tFDP Root Delete Page\n" ) );
+ (*pcprintf)( "\t\tFDP Root Delete Page\n" );
}
else if ( FPageFDPDelete() )
{
- (*pcprintf)( _T( "\t\tFDP Delete Page\n" ) );
+ (*pcprintf)( "\t\tFDP Delete Page\n" );
}
- (*pcprintf)( _T( "\t\tPageFlushType = %d\n" ), Pgft() );
+ (*pcprintf)( "\t\tPageFlushType = %d\n", Pgft() );
- (*pcprintf)( _T( "\n" ) );
+ (*pcprintf)( "\n" );
return JET_errSuccess;
}
diff --git a/dev/ese/src/ese/cpage_test.cxx b/dev/ese/src/ese/cpage_test.cxx
index 7ab18b08..f8ffb7c0 100644
--- a/dev/ese/src/ese/cpage_test.cxx
+++ b/dev/ese/src/ese/cpage_test.cxx
@@ -2293,6 +2293,7 @@ void CPageTestFixture::TestInternalTest()
void CPageTestFixture::TestRevertDbtimeCheckDbtime()
// ================================================================
{
+ m_cpage.Dirty_( bfdfDirty );
m_cpage.SetDbtime( 1 );
CHECK( 1 == m_cpage.Dbtime() );
m_cpage.SetDbtime( 2 );
@@ -2317,6 +2318,7 @@ void CPageTestFixture::TestRevertDbtimeCheckFlags()
m_cpage.SetFlags( fFlagsAfter );
CHECK( !m_cpage.FScrubbed() );
CHECK( fFlagsAfter == m_cpage.FFlags() );
+ m_cpage.Dirty_( bfdfDirty );
m_cpage.SetDbtime( 2 );
CHECK( 2 == m_cpage.Dbtime() );
m_cpage.RevertDbtime( 1, fFlagsBefore );
@@ -2324,29 +2326,43 @@ void CPageTestFixture::TestRevertDbtimeCheckFlags()
CHECK( !m_cpage.FScrubbed() );
CHECK( fFlagsAfter == m_cpage.FFlags() );
+ // Check scrub state is set/released correctly
+ CHECK( m_cpage.m_fPageScrubbedPrevSet );
+ m_cpage.ReleaseReadLatch();
+ CHECK( !m_cpage.m_fPageScrubbedPrevSet );
+
+ m_cpage.LoadNewPage( m_ifmp, m_pgno, m_objidFDP, m_fFlags, m_pvPage, CbPage_() );
+
// Scrub is unset and changes.
- fFlagsBefore = CPAGE::fPageLeaf | CPAGE::fPageLongValue;
+ fFlagsBefore = CPAGE::fPageLeaf | CPAGE::fPageLongValue | CPAGE::fPageRoot;
m_cpage.SetFlags( fFlagsBefore );
CHECK( !m_cpage.FScrubbed() );
CHECK( fFlagsBefore == m_cpage.FFlags() );
- fFlagsAfter = CPAGE::fPageLeaf | CPAGE::fPageLongValue | CPAGE::fPageRoot | CPAGE::fPageScrubbed;
- m_cpage.SetFlags( fFlagsAfter );
- CHECK( m_cpage.FScrubbed() );
- CHECK( fFlagsAfter == m_cpage.FFlags() );
+ fFlagsAfter = CPAGE::fPageLeaf | CPAGE::fPageLongValue | CPAGE::fPageRoot;
+ m_cpage.Dirty_( bfdfDirty );
+ m_cpage.SetFScrubbed_();
m_cpage.SetDbtime( 2 );
CHECK( 2 == m_cpage.Dbtime() );
m_cpage.RevertDbtime( 1, fFlagsBefore );
CHECK( 1 == m_cpage.Dbtime() );
CHECK( !m_cpage.FScrubbed() );
- CHECK( ( fFlagsAfter & ~CPAGE::fPageScrubbed ) == m_cpage.FFlags() );
+ CHECK( fFlagsAfter == m_cpage.FFlags() );
+
+ // Check scrub state is set/released correctly
+ CHECK( m_cpage.m_fPageScrubbedPrevSet );
+ m_cpage.ReleaseRDWLatch();
+ CHECK( !m_cpage.m_fPageScrubbedPrevSet );
+
+ m_cpage.LoadNewPage( m_ifmp, m_pgno, m_objidFDP, m_fFlags, m_pvPage, CbPage_() );
// Scrub is set and doesn't change.
- fFlagsBefore = CPAGE::fPageLeaf | CPAGE::fPageLongValue | CPAGE::fPageScrubbed;
+ fFlagsBefore = CPAGE::fPageLeaf | CPAGE::fPageLongValue | CPAGE::fPageRoot | CPAGE::fPageScrubbed;
m_cpage.SetFlags( fFlagsBefore );
CHECK( m_cpage.FScrubbed() );
CHECK( fFlagsBefore == m_cpage.FFlags() );
fFlagsAfter = CPAGE::fPageLeaf | CPAGE::fPageLongValue | CPAGE::fPageRoot | CPAGE::fPageScrubbed;
- m_cpage.SetFlags( fFlagsAfter );
+ m_cpage.Dirty_( bfdfDirty );
+ m_cpage.SetFScrubbed_();
CHECK( m_cpage.FScrubbed() );
CHECK( fFlagsAfter == m_cpage.FFlags() );
m_cpage.SetDbtime( 2 );
@@ -2356,21 +2372,24 @@ void CPageTestFixture::TestRevertDbtimeCheckFlags()
CHECK( m_cpage.FScrubbed() );
CHECK( fFlagsAfter == m_cpage.FFlags() );
+ // Check scrub state is set/released correctly
+ CHECK( m_cpage.m_fPageScrubbedPrevSet );
+ m_cpage.ReleaseWriteLatch();
+ CHECK( !m_cpage.m_fPageScrubbedPrevSet );
+
+ m_cpage.LoadNewPage( m_ifmp, m_pgno, m_objidFDP, m_fFlags, m_pvPage, CbPage_() );
+
// Scrub is set and changes.
- fFlagsBefore = CPAGE::fPageLeaf | CPAGE::fPageLongValue | CPAGE::fPageScrubbed;
+ fFlagsBefore = CPAGE::fPageLeaf | CPAGE::fPageLongValue | CPAGE::fPageRoot | CPAGE::fPageScrubbed;
m_cpage.SetFlags( fFlagsBefore );
CHECK( m_cpage.FScrubbed() );
CHECK( fFlagsBefore == m_cpage.FFlags() );
fFlagsAfter = CPAGE::fPageLeaf | CPAGE::fPageLongValue | CPAGE::fPageRoot;
- m_cpage.SetFlags( fFlagsAfter );
- CHECK( !m_cpage.FScrubbed() );
- CHECK( fFlagsAfter == m_cpage.FFlags() );
+ m_cpage.Dirty_( bfdfDirty );
m_cpage.SetDbtime( 2 );
CHECK( 2 == m_cpage.Dbtime() );
m_cpage.RevertDbtime( 1, fFlagsBefore );
CHECK( 1 == m_cpage.Dbtime() );
- CHECK( m_cpage.FScrubbed() );
- CHECK( fFlagsAfter == ( m_cpage.FFlags() & ~CPAGE::fPageScrubbed ) );
}
// ================================================================
diff --git a/dev/ese/src/ese/cresmgr.cxx b/dev/ese/src/ese/cresmgr.cxx
index 51d5f28e..a665df28 100644
--- a/dev/ese/src/ese/cresmgr.cxx
+++ b/dev/ese/src/ese/cresmgr.cxx
@@ -1882,7 +1882,7 @@ VOID CResourceManager::MarkAsFreed__(
//======================================
VOID CResourceManager::IDumpAlloc( const WCHAR* szDumpFile )
{
- CPRINTFFILE cprintf( szDumpFile );
+ CPRINTFFILE cprintf( szDumpFile, CPRINTFFILE::FILEENCODING::ASCII );
cprintf( "ResourceID = %i Tag: \"%.*s\" object size = %i\r\n\r\n",
ResID(),
@@ -3057,7 +3057,7 @@ VOID OSRMPostterm()
fOSRMPreinitPostTerm = fTrue;
#ifdef RM_STATISTICS
- CPRINTFFILE cprintf( "rmstat.txt" );
+ CPRINTFFILE cprintf( "rmstat.txt", fFalse );
cprintf( "\r\n\r\n%ws\r\n", WszUtilProcessName() );
cprintf( "RESID Alloc (RFOLWait) Free (WaitChnk WaitLoop WaitSucc) ( LAGACX LAGFst LAGHit) ( LARACX LARFst LARHit)\r\n" );
cprintf( "=================================================================================================================" );
diff --git a/dev/ese/src/ese/dataserializer.cxx b/dev/ese/src/ese/dataserializer.cxx
index cf51a7d4..814ee272 100644
--- a/dev/ese/src/ese/dataserializer.cxx
+++ b/dev/ese/src/ese/dataserializer.cxx
@@ -5,7 +5,6 @@
#include "PageSizeClean.hxx"
-
// ================================================================
// CPRINTFBUFFER
// ================================================================
@@ -21,12 +20,12 @@ class CPRINTFBUFFER : public CPRINTF
virtual ~CPRINTFBUFFER() {}
const char * SzBuffer() const { return m_szBuffer; }
- void __cdecl operator()( const _TCHAR* szFormat, ... )
+ void __cdecl operator()( const CHAR* szFormat, ... )
{
va_list arg_ptr;
va_start( arg_ptr, szFormat );
const size_t cchBufferUsed = strlen( m_szBuffer );
- StringCbVPrintfA( m_szBuffer + cchBufferUsed, m_cchBuffer - cchBufferUsed, szFormat, arg_ptr );
+ OSStrCbVFormatA( m_szBuffer + cchBufferUsed, m_cchBuffer - cchBufferUsed, szFormat, arg_ptr );
va_end( arg_ptr );
}
@@ -688,7 +687,7 @@ DataSerializer::~DataSerializer()
void DataSerializer::SetBindingsToDefault()
{
- for_each( m_bindings.begin(), m_bindings.end(), mem_fun( &DataBinding::SetToDefault ) );
+ for_each( m_bindings.begin(), m_bindings.end(), mem_fn( &DataBinding::SetToDefault ) );
}
ERR DataSerializer::ErrSaveBindings( IDataStore * const pstore )
diff --git a/dev/ese/src/ese/db.cxx b/dev/ese/src/ese/db.cxx
index a582d102..a9fa252c 100644
--- a/dev/ese/src/ese/db.cxx
+++ b/dev/ese/src/ese/db.cxx
@@ -1576,10 +1576,7 @@ ERR ErrDBParseDbParams(
if ( ( pgrbitShrinkDatabaseOptions != NULL ) &&
( ( *pgrbitShrinkDatabaseOptions &
~( JET_bitShrinkDatabaseEofOnAttach |
- JET_bitShrinkDatabaseFullCategorizationOnAttach |
- JET_bitShrinkDatabaseDontMoveRootsOnAttach |
- JET_bitShrinkDatabaseDontTruncateLeakedPagesOnAttach |
- JET_bitShrinkDatabaseDontTruncateIndeterminatePagesOnAttach ) ) != 0 ) )
+ JET_bitShrinkDatabaseFullCategorizationOnAttach ) ) != 0 ) )
{
return ErrERRCheck( JET_errInvalidGrbit );
}
@@ -2679,6 +2676,7 @@ ERR ErrDBReadHeaderCheckConsistency(
err = ErrUtilReadShadowedHeader( pfmp->Pinst(),
pfsapi,
pfapi,
+ JET_filetypeDatabase,
(BYTE*)pdbfilehdr,
g_cbPage,
OffsetOf( DBFILEHDR, le_cbPageSize ),
@@ -3958,6 +3956,7 @@ LOCAL ERR ErrDBIUpdateHeaderFromTrailer(
pinst,
pfsapi,
wszDatabase,
+ JET_filetypeDatabase,
reinterpret_cast( pdbfilehdr ),
g_cbPage,
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ),
@@ -5643,7 +5642,7 @@ ERR ISAMAPI ErrIsamDetachDatabase( JET_SESID sesid, IFileSystemAPI* const pfsapi
// 1. For the log writer it is OK to generate a new log w/o updating the header as no log operations
// for this db will be logged in new logs
// 2. For the checkpoint: don't advance the checkpoint if db's header weren't update
- Assert( pfmp->FAllowHeaderUpdate() || pfmp->FReadOnlyAttach() );
+ Assert( pfmp->FAllowHeaderUpdate() || pfmp->FReadOnlyAttach() || pfmp->FAttachedForRecovery() );
pfmp->RwlDetaching().EnterAsWriter();
pfmp->ResetAllowHeaderUpdate();
pfmp->RwlDetaching().LeaveAsWriter();
@@ -6185,6 +6184,7 @@ ERR ISAMAPI ErrIsamSetDatabaseSize( JET_SESID sesid, const WCHAR *wszDatabase, D
Call( ErrUtilReadShadowedHeader( PinstFromPpib( ppib ),
pfsapi,
pfapi,
+ JET_filetypeDatabase,
(BYTE *)pdbfilehdr,
g_cbPage,
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ) ) );
diff --git a/dev/ese/src/ese/dbdump.cxx b/dev/ese/src/ese/dbdump.cxx
index 0bc9717d..a8efe40e 100644
--- a/dev/ese/src/ese/dbdump.cxx
+++ b/dev/ese/src/ese/dbdump.cxx
@@ -522,6 +522,7 @@ ERR ErrDUMPHeader( INST *pinst, _In_ PCWSTR wszDatabase, const BOOL fVerbose )
{
headerRequestPrimaryOnly,
wszDatabase,
+ JET_filetypeUnknown,
NULL,
cbHeader,
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ),
@@ -537,6 +538,7 @@ ERR ErrDUMPHeader( INST *pinst, _In_ PCWSTR wszDatabase, const BOOL fVerbose )
{
headerRequestSecondaryOnly,
wszDatabase,
+ JET_filetypeUnknown,
NULL,
cbHeader,
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ),
@@ -674,6 +676,7 @@ ERR ErrDUMPFixupHeader( INST *pinst, _In_ PCWSTR wszDatabase, const BOOL fVerbos
{
headerRequestGoodOnly,
wszDatabase,
+ JET_filetypeUnknown,
NULL,
cbHeader,
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ),
diff --git a/dev/ese/src/ese/dbscan.cxx b/dev/ese/src/ese/dbscan.cxx
index 71eadf8f..247c1150 100644
--- a/dev/ese/src/ese/dbscan.cxx
+++ b/dev/ese/src/ese/dbscan.cxx
@@ -3711,7 +3711,7 @@ ERR DBMScanObserverCleanup::ErrCleanupLVPage_( CSR * const pcsr, DBMObjectCache*
}
LvId lid;
LidFromKey( &lid, kdf.key );
- CArray::ERR errT = arrLid.ErrSetEntry( arrLid.Size(), lid );
+ CArray::ERR errT = arrLid.ErrAppendEntry( lid );
Assert( errT == CArray::ERR::errSuccess );
}
}
@@ -3965,7 +3965,8 @@ ERR DBMScanObserverCleanup::ErrCleanupPrimaryPage_( CSR * const pcsr, DBMObjectC
// In ErrBTISinglePageCleanup, ErrBTISPCDeleteNodes will nullify the node's data (replace with
// a single byte NULL chSCRUBDBMaintEmptyPageLastNodeFill) but it can't remove the only node in
// the page (b-tree pages can't be empty), and return MultipageOLC. Then ErrBTIMultipageCleanup will
- // return wrnBTShallowTree without doing anything.
+ // return JET_errSuccess without doing anything (errBTShallowTree is returned from ErrBTICreateMergePath
+ // and translated into JET_errSuccess by ErrBTIMultipageCleanup).
//
// Avoid repeated replacing/scrubbing of case 1 pages
@@ -4652,9 +4653,9 @@ DBMScan::DBMScan(
m_ppib( ppib ),
m_cscanobservers( 0 ),
m_threadDBMScan( 0 ),
- m_critSignalControl( CLockBasicInfo( CSyncBasicInfo( _T("DBMScan::m_critSignalControl" ) ), rankDBMScanSignalControl, 0 ) ),
- m_msigDBScanStop( CSyncBasicInfo( _T("DBMScan::m_msigDBScanStop" ) ) ),
- m_msigDBScanGo( CSyncBasicInfo( _T("DBMScan::m_msigDBScanGo" ) ) ),
+ m_critSignalControl( CLockBasicInfo( CSyncBasicInfo( "DBMScan::m_critSignalControl" ), rankDBMScanSignalControl, 0 ) ),
+ m_msigDBScanStop( CSyncBasicInfo( "DBMScan::m_msigDBScanStop" ) ),
+ m_msigDBScanGo( CSyncBasicInfo( "DBMScan::m_msigDBScanGo" ) ),
m_pidbmScanSerializationObj( NULL ),
m_cscansFinished( 0 ),
m_fNeedToSuspendPass( false ),
@@ -5326,7 +5327,7 @@ DWORD DBMScanSerializer::DwTimeSlice() const
DBMScanSerializer::DBMScanSerializer( const ULONG_PTR ulKey ) :
IDBMScanSerializer( ulKey, IDBMScanSerializer::idbmstypReal ),
- m_critSerializer( CLockBasicInfo( CSyncBasicInfo( _T("DBMScanSerializer::m_critSerializer" ) ), rankDBMScanSerializer, 0 ) ),
+ m_critSerializer( CLockBasicInfo( CSyncBasicInfo( "DBMScanSerializer::m_critSerializer" ), rankDBMScanSerializer, 0 ) ),
m_ilDbmScans()
{
}
@@ -5541,7 +5542,7 @@ bool DBMScanSerializerFactory::FSerializerFactoryEmpty()
}
DBMScanSerializerFactory::DBMScanSerializerFactory() :
- m_critSerializer( CLockBasicInfo( CSyncBasicInfo( _T("DBMScanSerializerFactory::m_critSerializer" ) ), rankDBMScanSerializerFactory, 0 ) ),
+ m_critSerializer( CLockBasicInfo( CSyncBasicInfo( "DBMScanSerializerFactory::m_critSerializer" ), rankDBMScanSerializerFactory, 0 ) ),
m_ilSerializers(),
m_cDummySerializers( 0 )
{
@@ -6773,7 +6774,7 @@ TestDBMScanObserver::TestDBMScanObserver() :
m_fPrepareToTermCalled( false ),
m_cpgRead( 0 ),
m_pgnoBadChecksum( pgnoNull ),
- m_asigFinishedPass( CSyncBasicInfo( _T("TestDBMScanObserver::asigFinishedPass" ) ) )
+ m_asigFinishedPass( CSyncBasicInfo( "TestDBMScanObserver::asigFinishedPass" ) )
{
}
@@ -7166,7 +7167,7 @@ TestDBMScanReader::TestDBMScanReader( const PGNO pgnoLast, const PGNO pgnoBadChe
m_fInError( fFalse ),
m_pgnoLast( pgnoLast ),
m_pgnoBadChecksum( pgnoBadChecksum ),
- m_msigReadPageCalled( CSyncBasicInfo( _T("TestDBMScanReader::msigReadPageCalled" ) ) )
+ m_msigReadPageCalled( CSyncBasicInfo( "TestDBMScanReader::msigReadPageCalled" ) )
{
}
diff --git a/dev/ese/src/ese/dbshrink.cxx b/dev/ese/src/ese/dbshrink.cxx
index 32c2c8a8..eb7158a8 100644
--- a/dev/ese/src/ese/dbshrink.cxx
+++ b/dev/ese/src/ese/dbshrink.cxx
@@ -4,25 +4,21 @@
#include "std.hxx"
#include "errdata.hxx"
#include "_bt.hxx"
+#include "_space.hxx"
#include "PageSizeClean.hxx"
// Tracing.
//
-LOCAL ERR ErrSHKIShrinkEofTracingBegin( _In_ IFileSystemAPI * pfsapi, _In_ JET_PCWSTR wszDatabase, _Out_ CPRINTF** ppcprintfShrinkTraceRaw )
+LOCAL VOID SHKIShrinkEofTracingBegin( _In_ IFileSystemAPI * pfsapi, _In_ JET_PCWSTR wszDatabase, _Out_ CPRINTF** ppcprintfShrinkTraceRaw )
{
- ERR err = JET_errSuccess;
-
- Call( ErrBeginDatabaseIncReseedTracing( pfsapi, wszDatabase, ppcprintfShrinkTraceRaw ) );
+ (VOID)ErrBeginDatabaseIncReseedTracing( pfsapi, wszDatabase, ppcprintfShrinkTraceRaw );
(**ppcprintfShrinkTraceRaw)( "Beginning shrink pass.\r\n" );
-
-HandleError:
- return err;
}
-VOID SHKIShrinkEofTracingEnd( _Out_ CPRINTF** ppcprintfShrinkTraceRaw )
+LOCAL VOID SHKIShrinkEofTracingEnd( _Out_ CPRINTF** ppcprintfShrinkTraceRaw )
{
if ( *ppcprintfShrinkTraceRaw )
{
@@ -36,16 +32,33 @@ VOID SHKIShrinkEofTracingEnd( _Out_ CPRINTF** ppcprintfShrinkTraceRaw )
// Top-level shrink functions.
//
+typedef struct ShrinkExtMoveStats : public CZeroInit
+{
+ // .ctor
+ ShrinkExtMoveStats() : CZeroInit( sizeof( ShrinkExtMoveStats ) ) {}
+
+ // Data.
+ CPG cpgMoved;
+ CPG cpgShelved;
+ CPG cpgUnleaked;
+ CPG cpgRootMoved;
+ CPG cpgInternalMoved;
+ CPG cpgLeafMoved;
+ CPG cpgRootSpaceMoved;
+ CPG cpgInternalSpaceMoved;
+ CPG cpgLeafSpaceMoved;
+ ULONG cSmallSpaceTreesConverted;
+ HRT dhrtPageCategorization;
+ HRT dhrtPageProcessing;
+ HRT dhrtPageMoves;
+} ShrinkExtMoveStats;
+
LOCAL ERR ErrSHKIMoveLastExtent(
_In_ PIB* ppib,
_In_ const IFMP ifmp,
_In_ const HRT hrtStarted,
_In_ CPRINTF* const pcprintfShrinkTraceRaw,
- _Inout_ CPG* const pcpgMoved,
- _Inout_ CPG* const pcpgShelved,
- _Inout_ CPG* const pcpgUnleaked,
- _Inout_ HRT* const pdhrtPageCategorization,
- _Inout_ HRT* const pdhrtDataMove,
+ _Inout_ ShrinkExtMoveStats* const psems,
_Out_ ShrinkDoneReason* const psdr,
_Out_ PGNO* const ppgnoLastProcessed,
_Out_ PGNO* const pgnoFirstFromLastExtentMoved,
@@ -94,13 +107,9 @@ LOCAL ERR ErrSHKIMoveLastExtent(
SpaceCatCtx* pSpCatCtx = NULL;
BFLatch bfl;
BOOL fPageLatched = fFalse;
- BOOL fPageCategorization = fFalse;
- BOOL fDataMove = fFalse;
- HRT hrtPageCategorizationStart = 0;
- HRT hrtDataMoveStart = 0;
- CPG cpgMoved = 0;
- CPG cpgShelved = 0;
- CPG cpgUnleaked = 0;
+ BOOL fPageCategorization = fFalse, fPageProcessing = fFalse, fPageMove = fFalse;
+ HRT hrtPageCategorizationStart = 0, hrtPageProcessingStart = 0, hrtPageMoveStart = 0;
+ CPG cpgShelved = 0, cpgUnleaked = 0;
PIBTraceContextScope tcScope = ppib->InitTraceContextScope();
tcScope->iorReason.SetIort( iortDbShrink );
@@ -160,10 +169,16 @@ LOCAL ERR ErrSHKIMoveLastExtent(
{
while ( pgnoCurrent <= pgnoLast )
{
- if ( fDataMove )
+ if ( fPageProcessing )
+ {
+ psems->dhrtPageProcessing += DhrtHRTElapsedFromHrtStart( hrtPageProcessingStart );
+ fPageProcessing = fFalse;
+ }
+
+ if ( fPageMove )
{
- *pdhrtDataMove += DhrtHRTElapsedFromHrtStart( hrtDataMoveStart );
- fDataMove = fFalse;
+ psems->dhrtPageMoves += DhrtHRTElapsedFromHrtStart( hrtPageMoveStart );
+ fPageMove = fFalse;
}
// Resume to normal pass type if we're past the proper page or if
@@ -252,7 +267,7 @@ LOCAL ERR ErrSHKIMoveLastExtent(
&pSpCatCtx ) );
Assert( !FSPSpaceCatUnknown( spcatfCurrent ) ); // We should not get this here.
Assert( !FSPSpaceCatNotOwnedEof( spcatfCurrent ) ); // We should not get this here because we're only processing known-owned pages.
- *pdhrtPageCategorization += DhrtHRTElapsedFromHrtStart( hrtPageCategorizationStart );
+ psems->dhrtPageCategorization += DhrtHRTElapsedFromHrtStart( hrtPageCategorizationStart );
fPageCategorization = fFalse;
// It is not possible to handle these. The database is now effectively unshrinkable.
@@ -298,8 +313,8 @@ LOCAL ERR ErrSHKIMoveLastExtent(
*ppgnoLastProcessed = pgnoCurrent;
*pspcatfLastProcessed = spcatfCurrent;
- fDataMove = fTrue;
- hrtDataMoveStart = HrtHRTCount();
+ fPageProcessing = fTrue;
+ hrtPageProcessingStart = HrtHRTCount();
// Indeterminate and leaked pages share some common handling.
if ( FSPSpaceCatIndeterminate( spcatfCurrent ) || FSPSpaceCatLeaked( spcatfCurrent ) )
@@ -343,11 +358,10 @@ LOCAL ERR ErrSHKIMoveLastExtent(
goto HandleError;
}
- // Check if indeterminate-page handling is enabled and supported.
+ // Check if indeterminate-page handling is supported.
// Note that FMP::FEfvSupported() below checks for both DB and log versions, but JET_efvShelvedPages2
// only upgrades the DB version so technically, we wouldn't need to check for the log version.
- if ( pfmp->FShrinkDatabaseDontTruncateIndeterminatePagesOnAttach() ||
- !pfmp->FEfvSupported( JET_efvShelvedPages2 ) )
+ if ( !pfmp->FEfvSupported( JET_efvShelvedPages2 ) )
{
*psdr = sdrPageNotMovable;
goto HandleError;
@@ -364,13 +378,6 @@ LOCAL ERR ErrSHKIMoveLastExtent(
*psdr = sdrUnexpected;
goto HandleError;
}
-
- // Check if leaked-page handling is enabled.
- if ( pfmp->FShrinkDatabaseDontTruncateLeakedPagesOnAttach() )
- {
- *psdr = sdrPageNotMovable;
- goto HandleError;
- }
}
CPAGE cpage;
@@ -638,6 +645,7 @@ LOCAL ERR ErrSHKIMoveLastExtent(
}
Call( ErrSPBurstSpaceTrees( pSpCatCtx->pfucb ) );
+ psems->cSmallSpaceTreesConverted++;
// Next iteration will see the same page as large space and move it appropriately.
fMovedPage = fTrue;
@@ -694,8 +702,11 @@ LOCAL ERR ErrSHKIMoveLastExtent(
{
Assert( !FSPSpaceCatSmallSpace( spcatfCurrent ) );
- if ( !pfmp->FShrinkDatabaseDontMoveRootsOnAttach() && pfmp->FEfvSupported( JET_efvRootPageMove ) )
+ if ( pfmp->FEfvSupported( JET_efvRootPageMove ) )
{
+ fPageMove = fTrue;
+ hrtPageMoveStart = HrtHRTCount();
+
// Note that we currently only support moving all roots of a tree (root itself, OE and AE root)
// at the same time. So depending on what kind of root we are processing, we need to pass the
// actual root of the tree.
@@ -709,7 +720,9 @@ LOCAL ERR ErrSHKIMoveLastExtent(
fMovedPage = fTrue;
(*pcprintfShrinkTraceRaw)( "ShrinkMoveRoot[%I32u:%I32u:%I32u:%d]\r\n", objidCurrent, pgnoCurrent, pgnoFDP, (int)spcatfCurrent );
- cpgMoved += 3; // FDP + OE + AE.
+ psems->cpgMoved += 3; // FDP + OE + AE.
+ psems->cpgRootMoved++;
+ psems->cpgRootSpaceMoved += 2;
continue;
}
else
@@ -723,16 +736,34 @@ LOCAL ERR ErrSHKIMoveLastExtent(
if ( FSPSpaceCatStrictlyInternal( spcatfCurrent ) || FSPSpaceCatStrictlyLeaf( spcatfCurrent ) )
{
Assert( !FSPSpaceCatSmallSpace( spcatfCurrent ) );
+ Assert( objidCurrent != objidNil );
+
+ CPG cpgMoved = 0;
+ fPageMove = fTrue;
+ hrtPageMoveStart = HrtHRTCount();
const BOOL fSpacePage = FSPSpaceCatAnySpaceTree( spcatfCurrent );
+ Assert( ( objidCurrent != objidSystemRoot ) || fSpacePage );
- err = ErrBTPageMove(
+ if ( fSpacePage || !FSPSpaceCatStrictlyLeaf( spcatfCurrent ) || !BoolParam( JET_paramFlight_ContiguousExtentMoveShrinkEnabled ) )
+ {
+ err = ErrBTPageMove(
fSpacePage ? pSpCatCtx->pfucbSpace : pSpCatCtx->pfucb,
- *( pSpCatCtx->pbm ),
+ pSpCatCtx->pbmb->Bm(),
pgnoCurrent,
FSPSpaceCatStrictlyLeaf( spcatfCurrent ),
fSPNoFlags,
NULL );
+ cpgMoved = 1;
+ }
+ else
+ {
+ err = ErrBTContiguousExtentMove(
+ pSpCatCtx->pfucb,
+ pSpCatCtx->pbmb->Bm(),
+ pgnoCurrent,
+ &cpgMoved );
+ }
// If this is a space tree, we may need to retry because reserving split buffers
// for the move might have changed the page we're trying to move itself, which
@@ -750,15 +781,40 @@ LOCAL ERR ErrSHKIMoveLastExtent(
// exclusive access to the tree, so we must have been able to find the page
// with the passed in bookmark in the expected conditions (i.e., strictly internal
// or leaf).
- AssertTrack( ( err != wrnBTShallowTree ) && ( err != JET_errRecordNotFound ),
- OSFormat( ( err == wrnBTShallowTree ) ?
+ AssertTrack( ( err != errBTShallowTree ) && ( err != JET_errRecordNotFound ),
+ OSFormat( ( err == errBTShallowTree ) ?
"ShrinkMoveUnexpectedShallowBt:0x%I32x" : "ShrinkMoveUnexpectedNotFound:0x%I32x",
spcatfCurrent ) );
Call( err );
fMovedPage = fTrue;
(*pcprintfShrinkTraceRaw)( "ShrinkMove[%I32u:%I32u:%d]\r\n", objidCurrent, pgnoCurrent, (int)spcatfCurrent );
- cpgMoved++;
+ Assert( cpgMoved > 0 );
+ psems->cpgMoved += cpgMoved;
+ if ( FSPSpaceCatStrictlyLeaf( spcatfCurrent ) )
+ {
+ if ( fSpacePage )
+ {
+ Expected( cpgMoved == 1 );
+ psems->cpgLeafSpaceMoved += cpgMoved;
+ }
+ else
+ {
+ psems->cpgLeafMoved += cpgMoved;
+ }
+ }
+ else
+ {
+ Expected( cpgMoved == 1 );
+ if ( fSpacePage )
+ {
+ psems->cpgInternalSpaceMoved += cpgMoved;
+ }
+ else
+ {
+ psems->cpgInternalMoved += cpgMoved;
+ }
+ }
continue;
}
@@ -770,10 +826,16 @@ LOCAL ERR ErrSHKIMoveLastExtent(
goto HandleError;
} // end while ( pgnoCurrent <= pgnoLast )
- if ( fDataMove )
+ if ( fPageProcessing )
{
- *pdhrtDataMove += DhrtHRTElapsedFromHrtStart( hrtDataMoveStart );
- fDataMove = fFalse;
+ psems->dhrtPageProcessing += DhrtHRTElapsedFromHrtStart( hrtPageProcessingStart );
+ fPageProcessing = fFalse;
+ }
+
+ if ( fPageMove )
+ {
+ psems->dhrtPageMoves += DhrtHRTElapsedFromHrtStart( hrtPageMoveStart );
+ fPageMove = fFalse;
}
// If we made all the way with a lookup pending, go back and re-evaluate.
@@ -800,18 +862,25 @@ LOCAL ERR ErrSHKIMoveLastExtent(
} // end while ( fTrue )
HandleError:
- Assert( !( fPageCategorization && fDataMove ) );
+ Assert( !( fPageMove && !fPageProcessing ) );
+ Assert( !( fPageCategorization && fPageProcessing ) );
if ( fPageCategorization )
{
- *pdhrtPageCategorization += DhrtHRTElapsedFromHrtStart( hrtPageCategorizationStart );
+ psems->dhrtPageCategorization += DhrtHRTElapsedFromHrtStart( hrtPageCategorizationStart );
fPageCategorization = fFalse;
}
- if ( fDataMove )
+ if ( fPageProcessing )
{
- *pdhrtDataMove += DhrtHRTElapsedFromHrtStart( hrtDataMoveStart );
- fDataMove = fFalse;
+ psems->dhrtPageProcessing += DhrtHRTElapsedFromHrtStart( hrtPageProcessingStart );
+ fPageProcessing = fFalse;
+ }
+
+ if ( fPageMove )
+ {
+ psems->dhrtPageMoves += DhrtHRTElapsedFromHrtStart( hrtPageMoveStart );
+ fPageMove = fFalse;
}
if ( fPageLatched )
@@ -847,9 +916,8 @@ LOCAL ERR ErrSHKIMoveLastExtent(
AssertTrack( cpgUnleaked <= cpgLastOE, "ShrinkMoveTooManyPagesUnleaked" );
}
- *pcpgMoved += cpgMoved;
- *pcpgShelved += cpgShelved;
- *pcpgUnleaked += cpgUnleaked;
+ psems->cpgShelved += cpgShelved;
+ psems->cpgUnleaked += cpgUnleaked;
return err;
}
@@ -869,26 +937,28 @@ ERR ErrSHKShrinkDbFromEof(
FMP* const pfmp = g_rgfmp + ifmp;
INST* const pinst = pfmp->Pinst();
EXTENTINFO eiInitialOE, eiFinalOE;
- QWORD cbSizeFileInitial = 0;
- QWORD cbSizeFileFinal = 0;
- QWORD cbSizeOwnedInitial = 0;
- QWORD cbSizeOwnedFinal = 0;
+ QWORD cbSizeFileInitial = 0, cbSizeFileFinal = 0;
+ QWORD cbSizeOwnedInitial = 0, cbSizeOwnedFinal = 0;
CPRINTF* pcprintfShrinkTraceRaw = NULL;
const HRT hrtStarted = HrtHRTCount();
- CPG cpgMoved = 0, cpgShelved = 0, cpgUnleaked = 0;
+ ShrinkExtMoveStats sems;
ShrinkDoneReason sdr = sdrNone;
PGNO pgnoFirstFromLastExtentShrunkPrev = pgnoNull;
PGNO pgnoLastProcessed = pgnoNull;
+ PGNO pgnoShrinkTargetLast = pgnoMax;
SpaceCategoryFlags spcatfLastProcessed = spcatfNone;
- HRT dhrtExtMaint = 0;
- HRT dhrtFileTruncation = 0;
- HRT dhrtPageCategorization = 0;
- HRT dhrtDataMove = 0;
+ HRT dhrtExtMaint = 0, dhrtFileTruncation = 0;
BOOL fDbMayHaveChanged = fFalse;
Assert( !pfmp->FIsTempDB() );
- Call( ErrSHKIShrinkEofTracingBegin( pinst->m_pfsapi, g_rgfmp[ ifmp ].WszDatabaseName(), &pcprintfShrinkTraceRaw ) );
+ SHKIShrinkEofTracingBegin( pinst->m_pfsapi, g_rgfmp[ ifmp ].WszDatabaseName(), &pcprintfShrinkTraceRaw );
+
+ // First, delete any previously saved shrink archive files.
+ if ( !BoolParam( pinst, JET_paramFlight_EnableShrinkArchiving ) )
+ {
+ (void)ErrIODeleteShrinkArchiveFiles( ifmp );
+ }
// Bail out as early as possible if the database is already sufficiently small.
if ( pfmp->CpgOfCb( pfmp->CbOwnedFileSize() ) <= pfmp->CpgShrinkDatabaseSizeLimit() )
@@ -899,12 +969,6 @@ ERR ErrSHKShrinkDbFromEof(
Assert( !BoolParam( JET_paramEnableViewCache ) );
- // First, delete any previously saved shrink archive files.
- if ( !BoolParam( pinst, JET_paramFlight_EnableShrinkArchiving ) )
- {
- (void)ErrIODeleteShrinkArchiveFiles( ifmp );
- }
-
IFMP ifmpDummy;
Call( ErrDBOpenDatabase( ppib, pfmp->WszDatabaseName(), &ifmpDummy, JET_bitDbExclusive ) );
Assert( pfmp->FExclusiveBySession( ppib ) );
@@ -915,6 +979,7 @@ ERR ErrSHKShrinkDbFromEof(
// Open cursors to space trees.
Call( ErrSPGetLastExtent( ppib, ifmp, &eiInitialOE ) );
+ pgnoShrinkTargetLast = eiInitialOE.PgnoLast();
cbSizeOwnedInitial = OffsetOfPgno( eiInitialOE.PgnoLast() + 1 );
Assert( cbSizeOwnedInitial <= cbSizeFileInitial );
@@ -977,6 +1042,11 @@ ERR ErrSHKShrinkDbFromEof(
&sdr ),
DoneWithDataMove );
+ if ( pfmp->FPgnoShrinkTargetIsSet() )
+ {
+ pgnoShrinkTargetLast = pfmp->PgnoShrinkTarget();
+ }
+
Assert( pgnoFirstFromLastExtentTruncated != pgnoNull );
Assert( ( pgnoFirstFromLastExtentTruncated < pgnoFirstFromLastExtentTruncatedPrev ) ||
( pgnoFirstFromLastExtentTruncatedPrev == pgnoNull ) );
@@ -1022,17 +1092,15 @@ ERR ErrSHKShrinkDbFromEof(
ifmp,
hrtStarted,
pcprintfShrinkTraceRaw,
- &cpgMoved,
- &cpgShelved,
- &cpgUnleaked,
- &dhrtPageCategorization,
- &dhrtDataMove,
+ &sems,
&sdr,
&pgnoLastProcessed,
&pgnoFirstFromLastExtentMoved,
&spcatfLastProcessed ), DoneWithDataMove );
Assert( pgnoFirstFromLastExtentMoved == pgnoFirstFromLastExtentTruncated );
+ pgnoShrinkTargetLast = pfmp->FPgnoShrinkTargetIsSet() ? pfmp->PgnoShrinkTarget() : ( pgnoFirstFromLastExtentMoved - 1 );
+
// We've got signaled to stop.
if ( !pfmp->FShrinkIsActive() )
{
@@ -1078,9 +1146,17 @@ ERR ErrSHKShrinkDbFromEof(
HandleError:
#ifdef DEBUG
- Assert( cpgMoved >= 0 );
- Assert( cpgShelved >= 0 );
- Assert( cpgUnleaked >= 0 );
+ Assert( sems.cpgMoved >= 0 );
+ Assert( sems.cpgRootMoved >= 0 );
+ Assert( sems.cpgRootSpaceMoved >= 0 );
+ Assert( sems.cpgInternalMoved >= 0 );
+ Assert( sems.cpgInternalSpaceMoved >= 0 );
+ Assert( sems.cpgLeafMoved >= 0 );
+ Assert( sems.cpgLeafSpaceMoved >= 0 );
+ Assert( sems.cpgMoved == ( sems.cpgRootMoved + sems.cpgRootSpaceMoved + sems.cpgInternalMoved + sems.cpgInternalSpaceMoved + sems.cpgLeafMoved + sems.cpgLeafSpaceMoved ) );
+ Assert( sems.cpgShelved >= 0 );
+ Assert( sems.cpgUnleaked >= 0 );
+ Assert( sems.cSmallSpaceTreesConverted >= 0 );
Assert( err != errSPNoSpaceBelowShrinkTarget );
if ( err == JET_wrnShrinkNotPossible )
{
@@ -1151,6 +1227,40 @@ ERR ErrSHKShrinkDbFromEof(
// Emit event, except for when the database file was already small enough.
if ( ( sdr != sdrReachedSizeLimit ) || fDbMayHaveChanged )
{
+ // Calculate total available space below the last shrink target.
+ CPG cpgAvailBelowShrinkTarget = 0;
+ if ( pgnoShrinkTargetLast == pgnoMax )
+ {
+ EXTENTINFO ei;
+ if ( ErrSPGetLastExtent( ppib, ifmp, &ei ) >= JET_errSuccess )
+ {
+ pgnoShrinkTargetLast = ei.PgnoLast();
+ }
+ }
+ if ( pgnoShrinkTargetLast != pgnoMax )
+ {
+ PIBTraceContextScope tcScope = ppib->InitTraceContextScope();
+ tcScope->iorReason.SetIort( iortSpace );
+ FUCB *pfucbRoot = pfucbNil, *pfucbRootAe = pfucbNil;
+
+ if ( ( ErrBTIOpenAndGotoRoot( ppib, pgnoSystemRoot, ifmp, &pfucbRoot ) < JET_errSuccess ) ||
+ !pfucbRoot->u.pfcb->FSpaceInitialized() ||
+ ( ErrSPIOpenAvailExt( pfucbRoot, &pfucbRootAe ) < JET_errSuccess ) ||
+ ( ErrSPIGetInfo( pfucbRootAe, pgnoShrinkTargetLast, &cpgAvailBelowShrinkTarget, NULL, NULL, NULL, 0, NULL, NULL, NULL ) < JET_errSuccess ) )
+ {
+ cpgAvailBelowShrinkTarget = 0;
+ }
+ if ( pfucbRootAe != pfucbNil )
+ {
+ BTClose( pfucbRootAe );
+ }
+ if ( pfucbRoot != pfucbNil )
+ {
+ pfucbRoot->pcsrRoot = pcsrNil;
+ BTClose( pfucbRoot );
+ }
+ }
+
OSTraceSuspendGC();
const HRT dhrtElapsed = DhrtHRTElapsedFromHrtStart( hrtStarted );
const double dblSecTotalElapsed = DblHRTSecondsElapsed( dhrtElapsed );
@@ -1158,9 +1268,10 @@ ERR ErrSHKShrinkDbFromEof(
const double dblSecElapsed = dblSecTotalElapsed - (double)dwMinElapsed * 60.0;
dhrtExtMaint = min( dhrtExtMaint, dhrtElapsed );
dhrtFileTruncation = min( dhrtFileTruncation, dhrtElapsed );
- dhrtPageCategorization = min( dhrtPageCategorization, dhrtElapsed );
- dhrtDataMove = min( dhrtDataMove, dhrtElapsed );
- HRT dhrtRemaining = dhrtElapsed - ( dhrtExtMaint + dhrtFileTruncation + dhrtPageCategorization + dhrtDataMove );
+ sems.dhrtPageCategorization = min( sems.dhrtPageCategorization, dhrtElapsed );
+ sems.dhrtPageProcessing = min( sems.dhrtPageProcessing, dhrtElapsed );
+ sems.dhrtPageMoves = min( sems.dhrtPageMoves, dhrtElapsed );
+ HRT dhrtRemaining = dhrtElapsed - ( dhrtExtMaint + dhrtFileTruncation + sems.dhrtPageCategorization + sems.dhrtPageProcessing );
dhrtRemaining = max( dhrtRemaining, 0 );
const WCHAR* rgwsz[] =
{
@@ -1170,16 +1281,22 @@ ERR ErrSHKShrinkDbFromEof(
OSFormatW( L"%I64u", cbSizeFileFinal ), OSFormatW( L"%d", pfmp->CpgOfCb( cbSizeFileFinal ) ),
OSFormatW( L"%I64u", cbSizeOwnedInitial ), OSFormatW( L"%d", pfmp->CpgOfCb( cbSizeOwnedInitial ) ),
OSFormatW( L"%I64u", cbSizeOwnedFinal ), OSFormatW( L"%d", pfmp->CpgOfCb( cbSizeOwnedFinal ) ),
- OSFormatW( L"%I64u", pfmp->CbOfCpg( cpgMoved ) ), OSFormatW( L"%d", cpgMoved ),
+ OSFormatW( L"%I64u", pfmp->CbOfCpg( sems.cpgMoved ) ), OSFormatW( L"%d", sems.cpgMoved ),
OSFormatW( L"%d", err ),
OSFormatW( L"%I32u:%d:0x%08I32x", pgnoLastProcessed, (int)sdr, (DWORD)spcatfLastProcessed ),
OSFormatW( L"%.2f", ( 100.0 * (double)dhrtExtMaint ) / (double)dhrtElapsed ),
OSFormatW( L"%.2f", ( 100.0 * (double)dhrtFileTruncation ) / (double)dhrtElapsed ),
- OSFormatW( L"%.2f", ( 100.0 * (double)dhrtPageCategorization ) / (double)dhrtElapsed ),
- OSFormatW( L"%.2f", ( 100.0 * (double)dhrtDataMove ) / (double)dhrtElapsed ),
+ OSFormatW( L"%.2f", ( 100.0 * (double)sems.dhrtPageCategorization ) / (double)dhrtElapsed ),
+ OSFormatW( L"%.2f", ( 100.0 * (double)sems.dhrtPageProcessing ) / (double)dhrtElapsed ),
OSFormatW( L"%.2f", ( 100.0 * (double)dhrtRemaining ) / (double)dhrtElapsed ),
- OSFormatW( L"%d", cpgShelved ),
- OSFormatW( L"%d", cpgUnleaked )
+ OSFormatW( L"%d", sems.cpgShelved ),
+ OSFormatW( L"%d", sems.cpgUnleaked ),
+ OSFormatW( L"%.2f", ( 100.0 * (double)sems.dhrtPageMoves ) / (double)dhrtElapsed ),
+ OSFormatW( L"%lu", sems.cSmallSpaceTreesConverted ),
+ OSFormatW( L"%d", sems.cpgRootMoved ), OSFormatW( L"%d", sems.cpgRootSpaceMoved ),
+ OSFormatW( L"%d", sems.cpgInternalMoved ), OSFormatW( L"%d", sems.cpgInternalSpaceMoved ),
+ OSFormatW( L"%d", sems.cpgLeafMoved ), OSFormatW( L"%d", sems.cpgLeafSpaceMoved ),
+ OSFormatW( L"%I64u", pfmp->CbOfCpg( cpgAvailBelowShrinkTarget ) ), OSFormatW( L"%d", cpgAvailBelowShrinkTarget ),
};
UtilReportEvent(
( err < JET_errSuccess ) ? eventError : eventInformation,
@@ -1282,12 +1399,12 @@ LOCAL VOID SHKIRootMoveRevertDbTime( ROOTMOVE* const prm )
{
if ( prm->csrCatObj[iCat].Latch() == latchWrite )
{
- prm->csrCatObj[iCat].RevertDbtime( prm->dbtimeBeforeCatObj[iCat], prm->fFlagsBeforeCatObj[iCat] );
+ prm->csrCatObj[ iCat ].RevertDbtime( prm->dbtimeBeforeCatObj[ iCat ], prm->fFlagsBeforeCatObj[ iCat ] );
}
if ( prm->csrCatClustIdx[iCat].Latch() == latchWrite )
{
- prm->csrCatClustIdx[iCat].RevertDbtime( prm->dbtimeBeforeCatClustIdx[iCat], prm->fFlagsBeforeCatClustIdx[iCat] );
+ prm->csrCatClustIdx[ iCat ].RevertDbtime( prm->dbtimeBeforeCatClustIdx[ iCat ], prm->fFlagsBeforeCatClustIdx[ iCat ] );
}
}
}
@@ -1923,7 +2040,7 @@ LOCAL ERR ErrSHKIRootMoveCheck( const ROOTMOVE& rm, FUCB* const pfucb, const OBJ
pfucbChild->pcsrRoot = Pcsr( pfucbChild );
// Check against the previously enumerated objected.
- if ( PgnoSPIParentFDP( pfucbChild ) != rm.pgnoNewFDP )
+ if ( PgnoSPParentFDP( pfucbChild ) != rm.pgnoNewFDP )
{
AssertTrack( fFalse, "RootMoveBadPgnoParentFdp" );
Error( ErrERRCheck( JET_errDatabaseCorrupted ) );
@@ -2239,7 +2356,7 @@ ERR ErrSHKRootPageMove(
// This is because we will apply this root page move record only if we have preimages of both the source and destination.
if ( g_rgfmp[ ifmp ].FRBSOn() )
{
- Call( g_rgfmp[ ifmp ].PRBS()->ErrCaptureRootPageMove( g_rgfmp[ ifmp ].Dbid(), rm.pgnoFDP, rm.pgnoNewFDP ) );
+ Call( g_rgfmp[ ifmp ].PRBS()->ErrCaptureRootPageMove( g_rgfmp[ ifmp ].Dbid(), rm.pgnoFDP, rm.pgnoNewFDP, rm.dbtimeAfter ) );
}
// Re-open cursors and verify that the move looks consistent.
diff --git a/dev/ese/src/ese/dbutil.cxx b/dev/ese/src/ese/dbutil.cxx
index da846680..dc1ac32b 100644
--- a/dev/ese/src/ese/dbutil.cxx
+++ b/dev/ese/src/ese/dbutil.cxx
@@ -73,7 +73,7 @@ VOID DBUTLSprintHex(
if ( cbAddress )
{
- StringCbPrintfA( szDestCurrent, szDestMax - szDestCurrent + 1, "%*.*lx ", cbAddress, cbAddress, (INT)(pb - rgbSrc + cbStart) );
+ OSStrCbFormatA( szDestCurrent, szDestMax - szDestCurrent + 1, "%*.*lx ", cbAddress, cbAddress, (INT)(pb - rgbSrc + cbStart) );
(*szDestMax) = 0;
szDestCurrent += strlen(szDestCurrent);
@@ -5155,6 +5155,7 @@ LOCAL VOID DBUTLIReportSpaceLeakEstimationSucceeded(
const ULONG cUncachedPrimary,
const ULONG cEnumerationConflictsSucceeded,
const ULONG cEnumerationConflictsFailed,
+ const double dblSecTotalRetry,
const JET_THREADSTATS& jts,
const ULONG ulMinElapsed,
const double dblSecElapsed )
@@ -5193,7 +5194,8 @@ LOCAL VOID DBUTLIReportSpaceLeakEstimationSucceeded(
OSFormatW( L"%u", ulMinElapsed ), OSFormatW( L"%.3f", dblSecElapsed ),
OSFormatW( L"%d", cpgOwnedPrimaryCorrection ), OSFormatW( L"%I64d", pfmp->CbOfCpgSigned( cpgOwnedPrimaryCorrection ) ), ( ( cpgOwnedPrimaryOriginal != 0 ) ? OSFormatW( L"%.3f", ( 100.0 * (double)cpgOwnedPrimaryCorrection ) / (double)cpgOwnedPrimaryOriginal ) : L"-" ),
OSFormatW( L"%u", cEnumerationConflictsSucceeded ),
- OSFormatW( L"%u", cEnumerationConflictsFailed )
+ OSFormatW( L"%u", cEnumerationConflictsFailed ),
+ OSFormatW( L"%.3f", dblSecTotalRetry )
};
UtilReportEvent(
eventInformation,
@@ -5251,6 +5253,7 @@ LOCAL ERR ErrDBUTLIEstimateRootSpaceLeak( PIB* const ppib, const IFMP ifmp )
OBJID objidLast = objidNil;
PGNO pgnoFDPLast = pgnoNull;
ULONG cEnumerationConflictsFailed = 0, cEnumerationConflictsSucceeded = 0;
+ HRT dhrtEnumerationConflictsDuration = 0;
CPG cpgOwnedPrimary = 0, cpgOwnedPrimaryCorrection = 0;
ULONG cCachedPrimary = 0, cUncachedPrimary = 0;
CPG cpgUsedRoot = 0, cpgUsedOe = 0, cpgUsedAe = 0;
@@ -5304,7 +5307,7 @@ LOCAL ERR ErrDBUTLIEstimateRootSpaceLeak( PIB* const ppib, const IFMP ifmp )
}
else
{
- if ( ( err == JET_errRecordNotFound ) || ( err == JET_errNotInitialized ) )
+ if ( ( err == JET_errRecordNotFound ) || ( err == JET_errNotInitialized ) || ( err == JET_errRecordDeleted ) )
{
err = JET_errSuccess;
}
@@ -5313,17 +5316,26 @@ LOCAL ERR ErrDBUTLIEstimateRootSpaceLeak( PIB* const ppib, const IFMP ifmp )
// Test injection.
OnDebug( while ( objidLast >= (OBJID)UlConfigOverrideInjection( 48550, objidFDPOverMax ) ) );
- BOOL fRetried = fFalse, fRetry = fFalse;
+ double dblSecLeakReportRetryMax = 60.0;
+ const TICK dtickLeakReportRetrySleep = 10;
+ HRT hrtRetryStart = 0;
const BOOL fInfiniteRetries = OnDebugOrRetail( fTrue, fFalse );
+ BOOL fRetry = fFalse, fRetried = fFalse;
ERR errRetry = JET_errSuccess;
const CHAR* wszRetryReason = "";
do
{
- fRetried = fRetry;
if ( fRetry )
{
- UtilSleep( 10 );
fRetry = fFalse;
+
+ if ( !fRetried )
+ {
+ fRetried = fTrue;
+ hrtRetryStart = HrtHRTCount();
+ }
+
+ UtilSleep( dtickLeakReportRetrySleep );
}
err = ErrFILEOpenTable( ppib, ifmp, &pfucbTable, szObjectName, JET_bitTableReadOnly | JET_bitTableTryPurgeOnClose );
@@ -5331,28 +5343,38 @@ LOCAL ERR ErrDBUTLIEstimateRootSpaceLeak( PIB* const ppib, const IFMP ifmp )
{
// We are probably racing with table deletion.
FCBStateFlags fcbsf = fcbsfNone;
- const BOOL fFoundFcb = ( FCB::PfcbFCBGet( ifmp, pgnoFDPLast, &fcbsf, fFalse /* fIncrementRefCount */, fTrue /* fInitForRecovery */ ) != pfcbNil );
- const BOOL fDeletePending = fFoundFcb && ( fcbsf & fcbsfDeletePending );
-
- if ( fFoundFcb && !fDeletePending )
+ OBJID objidFcb = objidNil;
+ const BOOL fFoundFcb = ( FCB::PfcbFCBGet(
+ ifmp,
+ pgnoFDPLast,
+ &fcbsf,
+ fFalse, // fIncrementRefCount
+ fTrue, // fInitForRecovery
+ &objidFcb ) != pfcbNil ) &&
+ ( objidFcb == objidLast );
+ const BOOL fDeletePending = fFoundFcb && ( ( fcbsf & fcbsfDeletePending ) != 0 );
+
+ if ( fFoundFcb )
{
- // This is unexpected if we know the table is actually getting deleted.
- Assert( err != JET_errObjectNotFound );
- fRetry = fTrue;
- wszRetryReason = "DelNotPending";
- }
- else if ( fFoundFcb && fDeletePending )
- {
- // Table deletion is still pending.
- fRetry = fTrue;
- wszRetryReason = "DelPending";
+ if ( !fDeletePending )
+ {
+ // This is unexpected if we know the table is actually getting deleted.
+ Assert( err != JET_errObjectNotFound );
+ fRetry = fTrue;
+ wszRetryReason = "DelNotPending";
+ }
+ else
+ {
+ // Table deletion is still pending.
+ fRetry = fTrue;
+ wszRetryReason = "DelPending";
- // Perform cleanup.
- (void)PverFromPpib( ppib )->ErrVERRCEClean( ifmp );
+ // Perform cleanup: it may not help if an open transaction is holding us up.
+ (void)PverFromPpib( ppib )->ErrVERRCEClean( ifmp );
+ }
}
else
{
- Assert( !fFoundFcb );
if ( err == JET_errTableLocked )
{
// Either the version store entry for the table deletion has cleared,
@@ -5396,26 +5418,43 @@ LOCAL ERR ErrDBUTLIEstimateRootSpaceLeak( PIB* const ppib, const IFMP ifmp )
pfucbTable = pfucbNil;
}
- if ( fRetried )
+ if ( fRetry )
{
- if ( fRetry )
+ if ( !fInfiniteRetries )
{
- cEnumerationConflictsFailed++;
- if ( !fInfiniteRetries )
+ if ( fRetried )
{
- FireWall( OSFormat( "LeakReportConflict:%s:%d", wszRetryReason, errRetry ) );
+ // If we've previously failed, there's no point in trying hard to resolve conflicts, as the
+ // data will be unreliable anwyways, so reduce the retry timeout.
+ if ( cEnumerationConflictsFailed > 0 )
+ {
+ dblSecLeakReportRetryMax = 0.010;
+ }
+
+ if ( DblHRTSecondsElapsed( DhrtHRTElapsedFromHrtStart( hrtRetryStart ) ) >= dblSecLeakReportRetryMax )
+ {
+ fRetry = fFalse;
+ dhrtEnumerationConflictsDuration += DhrtHRTElapsedFromHrtStart( hrtRetryStart );
+ cEnumerationConflictsFailed++;
+ FireWall( OSFormat( "LeakReportConflict:%s:%d", wszRetryReason, errRetry ) );
+ }
}
}
else
{
- cEnumerationConflictsSucceeded++;
+ cEnumerationConflictsFailed++;
}
}
+ else if ( fRetried )
+ {
+ dhrtEnumerationConflictsDuration += DhrtHRTElapsedFromHrtStart( hrtRetryStart );
+ cEnumerationConflictsSucceeded++;
+ }
Assert( pfucbTable == pfucbNil );
Assert( err >= JET_errSuccess );
}
- while ( fRetry && ( !fRetried || fInfiniteRetries ) );
+ while ( fRetry );
}
pfmp->SetOjidLeakEstimation( objidLast );
@@ -5562,6 +5601,7 @@ LOCAL ERR ErrDBUTLIEstimateRootSpaceLeak( PIB* const ppib, const IFMP ifmp )
ppib->ResetFSessionLeakReport();
const double dblSecTotalElapsed = DblHRTSecondsElapsed( DhrtHRTElapsedFromHrtStart( hrtStart ) );
+ const double dblSecTotalRetry = DblHRTSecondsElapsed( dhrtEnumerationConflictsDuration );
const ULONG ulMinElapsed = (ULONG)( dblSecTotalElapsed / 60.0 );
const double dblSecElapsed = dblSecTotalElapsed - (double)ulMinElapsed * 60.0;
if ( err >= JET_errSuccess )
@@ -5588,6 +5628,7 @@ LOCAL ERR ErrDBUTLIEstimateRootSpaceLeak( PIB* const ppib, const IFMP ifmp )
cUncachedPrimary,
cEnumerationConflictsSucceeded,
cEnumerationConflictsFailed,
+ dblSecTotalRetry,
jts,
ulMinElapsed,
dblSecElapsed );
@@ -5775,6 +5816,7 @@ ERR ISAMAPI ErrIsamDBUtilities( JET_SESID sesid, JET_DBUTIL_W *pdbutil )
err = ErrUtilReadShadowedHeader( pinst,
pinst->m_pfsapi,
pfapi,
+ JET_filetypeDatabase,
(BYTE*)pdbfilehdr,
g_cbPage,
OffsetOf( DBFILEHDR, le_cbPageSize ),
diff --git a/dev/ese/src/ese/dir.cxx b/dev/ese/src/ese/dir.cxx
index a98b12a4..5578125b 100644
--- a/dev/ese/src/ese/dir.cxx
+++ b/dev/ese/src/ese/dir.cxx
@@ -304,9 +304,14 @@ ERR ErrDIROpenByProxy( PIB *ppib, FCB *pfcb, FUCB **ppfucb, LEVEL level )
CheckPIB( ppib );
#ifdef DEBUG
+ // We may be opening a proxy cursor using a system PIB.
+ // (e.g. if concurrent index create is processing an RCE created by a DBTASK such as FINALIZETASK).
+ // We don't call ErrDBOpenDatabase() for any DBTASKs, so the CheckDBID() call below needs to be skipped for that case.
+ // See VSO# 241238: AssertFail: "FPIBUserOpenedDatabase( ppib, rgfmp[ifmp].Dbid() )" from VER::ErrVERModify
INST *pinst = PinstFromPpib( ppib );
if ( !pinst->FRecovering()
&& pinst->m_fSTInit == fSTInitDone
+ && !ppib->FSystemCallback() // system PIBs may not call ErrDBOpenDatabase()
&& !Ptls()->FIsTaskThread()
&& !Ptls()->fIsRCECleanup )
{
@@ -1856,7 +1861,7 @@ ERR ErrDIRBeginTransaction( PIB *ppib, const TRXID trxid, const JET_GRBIT grbit
else
ppib->ResetFReadOnlyTrx();
- PIBSetTrxBegin0( ppib );
+ ppib->PIBSetTrxBegin0();
}
else if( prceNil != ppib->prceNewest )
{
diff --git a/dev/ese/src/ese/eselibwithtests/CMakeLists.txt b/dev/ese/src/ese/eselibwithtests/CMakeLists.txt
index 98d4511c..3215e9e1 100644
--- a/dev/ese/src/ese/eselibwithtests/CMakeLists.txt
+++ b/dev/ese/src/ese/eselibwithtests/CMakeLists.txt
@@ -39,6 +39,7 @@ add_library(eselibwithtests SHARED
# Tests
daehelpers_test.cxx
+ ../bbtbuff_test.cxx
../clogredomaps_test.cxx
../cpage_test.cxx
../checksum_test.cxx
diff --git a/dev/ese/src/ese/esent.def b/dev/ese/src/ese/esent.def
index 16afedb5..242d95f4 100644
--- a/dev/ese/src/ese/esent.def
+++ b/dev/ese/src/ese/esent.def
@@ -322,6 +322,9 @@ EXPORTS
ALIAS1(JetDupSession,8)
ALIAS2(JetDupSession,8)
+ ALIAS1(JetDupSession2,12)
+ ALIAS2(JetDupSession2,12)
+
ALIAS1(JetEnableMultiInstanceA,12)
ALIAS2(JetEnableMultiInstanceA,12)
ALIAS1(JetEnableMultiInstanceW,12)
diff --git a/dev/ese/src/ese/fcb.cxx b/dev/ese/src/ese/fcb.cxx
index 3c851132..cd866ad5 100644
--- a/dev/ese/src/ese/fcb.cxx
+++ b/dev/ese/src/ese/fcb.cxx
@@ -734,11 +734,12 @@ VOID FCB::UnlinkIDB( FCB *pfcbTable )
// NOTE: this is the proper channel for accessing an FCB; it uses the locking
// protocol setup by the FCB hash-table and FCB latch
-FCB *FCB::PfcbFCBGet( const IFMP ifmp, const PGNO pgnoFDP, FCBStateFlags* const pfcbsf, const BOOL fIncrementRefCount, const BOOL fInitForRecovery )
+FCB *FCB::PfcbFCBGet( const IFMP ifmp, const PGNO pgnoFDP, FCBStateFlags* const pfcbsf, const BOOL fIncrementRefCount, const BOOL fInitForRecovery, OBJID* const pobjid )
{
FCBStateFlags fcbsf = fcbsfNone;
INST *pinst = PinstFromIfmp( ifmp );
FCB *pfcbT;
+ OBJID objid = objidNil;
FCBHash::ERR errFCBHash;
FCBHash::CLock lockFCBHash;
FCBHashKey keyFCBHash( ifmp, pgnoFDP );
@@ -881,7 +882,7 @@ FCB *FCB::PfcbFCBGet( const IFMP ifmp, const PGNO pgnoFDP, FCBStateFlags* const
Assert( fcbsf == fcbsfNone );
fcbsf |= fcbsfInitialized;
fcbsf |= ( pfcbT->FDeletePending() ? fcbsfDeletePending : fcbsfNone );
-
+ objid = pfcbT->ObjidFDP();
// If this is the dummy FCB created by recovery, we need to fully populate
// it, make sure that the others wait while the first person finishes doing it
@@ -910,6 +911,7 @@ FCB *FCB::PfcbFCBGet( const IFMP ifmp, const PGNO pgnoFDP, FCBStateFlags* const
// try to get the FCB again
fcbsf = fcbsfNone;
+ objid = objidNil;
cRetries++;
goto RetrieveFCB;
@@ -929,11 +931,16 @@ FCB *FCB::PfcbFCBGet( const IFMP ifmp, const PGNO pgnoFDP, FCBStateFlags* const
SetStateAndReturn:
// set the state
Assert( ( pfcbT == pfcbNil ) == ( fcbsf == fcbsfNone ) ); // Pointer and flag must agree.
+ Assert( ( pfcbT == pfcbNil ) == ( objid == objidNil ) ); // Pointer and OBJID must agree.
Assert( ( fcbsf == fcbsfNone ) || ( fcbsf & fcbsfInitialized ) ); // Can't have any flags set if it's not initialized.
if ( pfcbsf )
{
*pfcbsf = fcbsf;
}
+ if ( pobjid )
+ {
+ *pobjid = objid;
+ }
// return the FCB
Assert( ( pfcbNil == pfcbT ) || ( pfcbT->IsUnlocked_( LOCK_TYPE::ltShared ) && pfcbT->IsUnlocked_( LOCK_TYPE::ltWrite ) ) );
diff --git a/dev/ese/src/ese/fcreate.cxx b/dev/ese/src/ese/fcreate.cxx
index d2ef7e31..fada7fb9 100644
--- a/dev/ese/src/ese/fcreate.cxx
+++ b/dev/ese/src/ese/fcreate.cxx
@@ -3015,6 +3015,8 @@ ERR ErrFILECreateTable( PIB *ppib, IFMP ifmp, JET_TABLECREATE5_A *ptablecreate,
return JET_errSuccess;
HandleError:
+ Assert( err != JET_errKeyDuplicate ); // should return JET_errTableDuplicate
+
OSTraceFMP(
ifmp,
JET_tracetagDDLWrite,
diff --git a/dev/ese/src/ese/fldext.cxx b/dev/ese/src/ese/fldext.cxx
index 56908843..15ad4a6a 100644
--- a/dev/ese/src/ese/fldext.cxx
+++ b/dev/ese/src/ese/fldext.cxx
@@ -569,7 +569,131 @@ ERR ErrRECIRetrieveTaggedColumn(
}
if ( dataRec.Cb() < REC::cbRecordMin || dataRec.Cb() > REC::CbRecordMostCHECK( g_rgfmp[ pfcb->Ifmp() ].CbPage() ) )
{
- FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1" );
+ const LONG cbRec = dataRec.Cb();
+ const LONG cbRecMost = REC::CbRecordMostCHECK( g_rgfmp[ pfcb->Ifmp() ].CbPage() );
+
+ if ( cbRec < REC::cbRecordMin )
+ {
+ if ( cbRec == 0 )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.Cb0" );
+ }
+ else if ( cbRec >= 0 && cbRec < REC::cbRecordMin )
+ {
+ static_assert( REC::cbRecordMin == 4 );
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.Cb1to3" );
+ }
+ else if ( cbRec > -4 )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.NegativeCbByUpToDword" );
+ }
+ else if ( cbRec > -16 )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.NegativeCbByUpTo16B" );
+ }
+ else if ( cbRec > -( cbRecMost / 2 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.NegativeCbByUpToHalfRecMost" );
+ }
+ else if ( cbRec > -( cbRecMost ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.NegativeCbByUpToRecMost" );
+ }
+ else if ( cbRec > -( cbRecMost * 2 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.NegativeCbByUpToRecMostX2" );
+ }
+ else if ( cbRec > -( 64 * 1024 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.NegativeCbByUpTo64K" );
+ }
+ else if ( cbRec > -( 128 * 1024 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.NegativeCbByUpTo128K" );
+ }
+ else if ( cbRec > -( 1024 * 1024 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.NegativeCbByUpTo1M" );
+ }
+ else if ( cbRec > -( 1024 * 1024 * 1024 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.NegativeCbByUpTo1G" );
+ }
+ else if ( cbRec >= lMin )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooSmall14.1.NegativeCbByUpTo2G" );
+ }
+ else
+ {
+ // This shouldn't be able to happen at all, unless dataRec was like being modified while we tested
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbTooSmallHow" ); // !!!?
+ }
+ }
+ else if ( cbRec > cbRecMost )
+ {
+ if ( cbRec == cbRecMost )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbEqualsMost" );
+ }
+ else if ( cbRec < ( cbRecMost + 4 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbUpToDwordOverMost" );
+ }
+ else if ( cbRec < ( cbRecMost + 16 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbUpTo16BOverMost" );
+ }
+ else if ( cbRec < ( cbRecMost + cbRecMost / 2 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbUpTo50PctOverMost" );
+ }
+ else if ( cbRec < ( cbRecMost * 2 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbUpToX2OverMost" );
+ }
+ else if ( cbRec < ( 64 * 1024 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbUpTo64KOverMost" );
+ }
+ else if ( cbRec < ( 128 * 1024 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbUpTo128KOverMost" );
+ }
+ else if ( cbRec < ( 1024 * 1024 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbUpTo1MOverMost" );
+ }
+ else if ( cbRec < ( 1024 * 1024 * 1024 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbUpTo1GOverMost" );
+ }
+ else if ( cbRec < ( (ULONG)2 * 1024 * 1024 * 1024 - 1 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbUpTo2GOverMost" );
+ }
+ else
+ {
+ // should be impossible, as the value is a LONG
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.CbGtrThan2GOverMost" );
+ }
+
+ if ( cbRecMost < 4000 )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecMostCuriouslySmall" );
+ }
+ // yes this cbPage is too small for possibly other Exchange clients, but the whole branch is
+ // processing invalid data.
+ else if ( g_rgfmp[ pfcb->Ifmp() ].CbPage() != ( 32 * 1024 ) || cbRecMost < ( 32 * 1000 ) )
+ {
+ FireWall( "RECIRetrieveTaggedColumnsRecMostOrPageSizeOdd" );
+ }
+ }
+ else
+ {
+ // This shouldn't be able to happen at all, unless dataRec was like being modified while we tested
+ FireWall( "RECIRetrieveTaggedColumnsRecTooBig14.1.VoltaileValues" );
+ }
+
return ErrERRCheck( JET_errDatabaseCorrupted );
}
diff --git a/dev/ese/src/ese/fmp.cxx b/dev/ese/src/ese/fmp.cxx
index 9735b481..1382e2aa 100644
--- a/dev/ese/src/ese/fmp.cxx
+++ b/dev/ese/src/ese/fmp.cxx
@@ -321,16 +321,16 @@ FMP::FMP()
: CZeroInit( sizeof( FMP ) ),
m_critLatch( CLockBasicInfo( CSyncBasicInfo( szFMP ), rankFMP, 0 ) ),
m_critDbtime( CLockBasicInfo( CSyncBasicInfo( szDbtime ), rankDbtime, 0 ) ),
- m_gateWriteLatch( CSyncBasicInfo( _T( "FMP::m_gateWriteLatch" ) ) ),
+ m_gateWriteLatch( CSyncBasicInfo( "FMP::m_gateWriteLatch" ) ),
m_semRangeLock( CSyncBasicInfo( "FMP::m_semRangeLock" ) ),
m_dbid( dbidMax ),
m_rwlDetaching( CLockBasicInfo( CSyncBasicInfo( szFMPDetaching ), rankFMPDetaching, 0 ) ),
m_rwlBFContext( CLockBasicInfo( CSyncBasicInfo( szBFFMPContext ), rankBFFMPContext, 0 ) ),
m_sxwlRedoMaps( CLockBasicInfo( CSyncBasicInfo( szFMPRedoMaps ), rankFMPRedoMaps, 0 ) ),
- m_semIOSizeChange( CSyncBasicInfo( _T( "FMP::m_semIOSizeChange" ) ) ),
+ m_semIOSizeChange( CSyncBasicInfo( "FMP::m_semIOSizeChange" ) ),
m_cAsyncIOForViewCachePending( 0 ),
- m_semTrimmingDB( CSyncBasicInfo( _T( "FMP::m_semTrimmingDB" ) ) ),
- m_semDBM( CSyncBasicInfo( _T( "FMP::m_semDBM" ) ) ),
+ m_semTrimmingDB( CSyncBasicInfo( "FMP::m_semTrimmingDB" ) ),
+ m_semDBM( CSyncBasicInfo( "FMP::m_semDBM" ) ),
m_isdlCreate( isdltypeCreate ),
m_isdlAttach( isdltypeAttach ),
m_isdlDetach( isdltypeDetach ),
@@ -1311,7 +1311,7 @@ ERR FMP::ErrNewAndWriteLatch(
memset( pdbfilehdr, 0, g_cbPage );
// read in db header
// note: read will fail from the newly created database path (when createdatabase() calls us)
- const ERR errRH = ErrUtilReadShadowedHeader( pinst, pfsapi, wszDatabaseName, (BYTE*)pdbfilehdr, g_cbPage, -1, UtilReadHeaderFlags( urhfReadOnly | urhfNoEventLogging ) );
+ const ERR errRH = ErrUtilReadShadowedHeader( pinst, pfsapi, wszDatabaseName, JET_filetypeDatabase, (BYTE*)pdbfilehdr, g_cbPage, -1, UtilReadHeaderFlags( urhfReadOnly | urhfNoEventLogging ) );
if ( errRH >= JET_errSuccess )
{
AssertDatabaseHeaderConsistent( pdbfilehdr, g_cbPage, g_cbPage );
diff --git a/dev/ese/src/ese/fmp_test.cxx b/dev/ese/src/ese/fmp_test.cxx
index 4f130c48..25d500cf 100644
--- a/dev/ese/src/ese/fmp_test.cxx
+++ b/dev/ese/src/ese/fmp_test.cxx
@@ -356,45 +356,15 @@ JETUNITTEST( FMP, NewAndWriteLatch )
// Verify shrink options.
CHECK( !pfmp->FShrinkDatabaseEofOnAttach() );
CHECK( !pfmp->FRunShrinkDatabaseFullCatOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontMoveRootsOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateLeakedPagesOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateIndeterminatePagesOnAttach() );
pfmp->SetShrinkDatabaseOptions( JET_bitShrinkDatabaseEofOnAttach );
CHECK( pfmp->FShrinkDatabaseEofOnAttach() );
CHECK( !pfmp->FRunShrinkDatabaseFullCatOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontMoveRootsOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateLeakedPagesOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateIndeterminatePagesOnAttach() );
pfmp->SetShrinkDatabaseOptions( JET_bitShrinkDatabaseFullCategorizationOnAttach );
CHECK( !pfmp->FShrinkDatabaseEofOnAttach() );
CHECK( pfmp->FRunShrinkDatabaseFullCatOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontMoveRootsOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateLeakedPagesOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateIndeterminatePagesOnAttach() );
- pfmp->SetShrinkDatabaseOptions( JET_bitShrinkDatabaseDontMoveRootsOnAttach );
- CHECK( !pfmp->FShrinkDatabaseEofOnAttach() );
- CHECK( !pfmp->FRunShrinkDatabaseFullCatOnAttach() );
- CHECK( pfmp->FShrinkDatabaseDontMoveRootsOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateLeakedPagesOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateIndeterminatePagesOnAttach() );
- pfmp->SetShrinkDatabaseOptions( JET_bitShrinkDatabaseDontTruncateLeakedPagesOnAttach );
- CHECK( !pfmp->FShrinkDatabaseEofOnAttach() );
- CHECK( !pfmp->FRunShrinkDatabaseFullCatOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontMoveRootsOnAttach() );
- CHECK( pfmp->FShrinkDatabaseDontTruncateLeakedPagesOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateIndeterminatePagesOnAttach() );
- pfmp->SetShrinkDatabaseOptions( JET_bitShrinkDatabaseDontTruncateIndeterminatePagesOnAttach );
- CHECK( !pfmp->FShrinkDatabaseEofOnAttach() );
- CHECK( !pfmp->FRunShrinkDatabaseFullCatOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontMoveRootsOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateLeakedPagesOnAttach() );
- CHECK( pfmp->FShrinkDatabaseDontTruncateIndeterminatePagesOnAttach() );
pfmp->SetShrinkDatabaseOptions( NO_GRBIT );
CHECK( !pfmp->FShrinkDatabaseEofOnAttach() );
CHECK( !pfmp->FRunShrinkDatabaseFullCatOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontMoveRootsOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateLeakedPagesOnAttach() );
- CHECK( !pfmp->FShrinkDatabaseDontTruncateIndeterminatePagesOnAttach() );
// Verify shrink time quota.
CHECK( -1 == pfmp->DtickShrinkDatabaseTimeQuota() );
@@ -439,6 +409,7 @@ JETUNITTEST( FMP, NewAndWriteLatch )
pfmp->SetPgnoShrinkTarget( 10 );
CHECK( pfmp->FShrinkIsActive() );
CHECK( pfmp->FPgnoShrinkTargetIsSet() );
+ CHECK( 10 == pfmp->PgnoShrinkTarget() );
CHECK( !pfmp->FBeyondPgnoShrinkTarget( pgnoNull ) );
CHECK( !pfmp->FBeyondPgnoShrinkTarget( pgnoNull, 0 ) );
CHECK( !pfmp->FBeyondPgnoShrinkTarget( pgnoNull, 1 ) );
diff --git a/dev/ese/src/ese/fucb.cxx b/dev/ese/src/ese/fucb.cxx
index 01643d66..375f8e05 100644
--- a/dev/ese/src/ese/fucb.cxx
+++ b/dev/ese/src/ese/fucb.cxx
@@ -373,7 +373,7 @@ VOID FUCBIllegalOperationFDPToBeDeleted(
const OBJID objidFDP )
{
// only report the error if not repairing
- if ( !g_fRepair )
+ if ( !g_fRepair && BoolParam( PinstFromPfucb( pfucb ), JET_paramFlight_RBSRaiseCorruptionOnRBSFDPToBeDeleted ) )
{
OSTraceSuspendGC();
WCHAR wszTableName[JET_cbNameMost+1] = L"";
@@ -381,7 +381,7 @@ VOID FUCBIllegalOperationFDPToBeDeleted(
if ( pfcbTable != NULL && pfcbTable->Ptdb() != NULL && pfcbTable->Ptdb()->SzTableName() != NULL )
{
- OSStrCbFormatW( wszTableName, sizeof(wszTableName), L"%hs", pfucb->u.pfcb->Ptdb()->SzTableName() );
+ OSStrCbFormatW( wszTableName, sizeof(wszTableName), L"%hs", pfcbTable->Ptdb()->SzTableName() );
}
const WCHAR* rgwsz[] =
diff --git a/dev/ese/src/ese/genapitable.pl b/dev/ese/src/ese/genapitable.pl
index 486ca9b8..412bc4ee 100644
--- a/dev/ese/src/ese/genapitable.pl
+++ b/dev/ese/src/ese/genapitable.pl
@@ -63,7 +63,7 @@
print OUTPUTFILE < 0 )
{
- err = ErrOSEncryptionVerifyKey( (BYTE*)pvParam, cbParam );
+ err = ErrOSEncryptionVerifyKey( PARAM_AES256_IMPLEMENTATION, (BYTE*)pvParam, cbParam );
if ( err < JET_errSuccess )
{
AssertSz( fFalse, "Client is giving us a bad key" );
return err;
}
+#ifdef DEBUG
+ // On debug, also verify with the other implementation
+ CallS( ErrOSEncryptionVerifyKey( OTHER_AES256_IMPLEMENTATION, (BYTE*)pvParam, cbParam ) );
+#endif
AllocR( pfucb->pbEncryptionKey = (BYTE*)PvOSMemoryHeapAlloc( cbParam ) );
memcpy( pfucb->pbEncryptionKey, pvParam, cbParam );
pfucb->cbEncryptionKey = cbParam;
@@ -1606,7 +1610,7 @@ ERR VTAPI ErrIsamGetTableInfo(
#ifdef DEBUG
if ( pfucb->cbEncryptionKey > 0 )
{
- ERR errT = ErrOSEncryptionVerifyKey( pfucb->pbEncryptionKey, pfucb->cbEncryptionKey );
+ ERR errT = ErrOSEncryptionVerifyKey( PARAM_AES256_IMPLEMENTATION, pfucb->pbEncryptionKey, pfucb->cbEncryptionKey );
if ( errT < JET_errSuccess )
{
AssertSz( fFalse, "Client should not have been able to save a bad encryption key" );
diff --git a/dev/ese/src/ese/io.cxx b/dev/ese/src/ese/io.cxx
index a6629e4a..e3338bec 100644
--- a/dev/ese/src/ese/io.cxx
+++ b/dev/ese/src/ese/io.cxx
@@ -1286,9 +1286,8 @@ ERR ErrIOResizeUpdateDbHdrLgposLast( const IFMP ifmp, const LGPOS& lgposLastResi
}
else if ( icmpLgposLastVsCurrent < 0 )
{
- Assert( !pfmp->FShrinkDatabaseEofOnAttach() &&
- ( PinstFromIfmp( ifmp )->m_plog->FRecoveringMode() == fRecoveringRedo ) );
-
+ // we don't expect to ever go back under normal resize conditions.
+ Assert( fFalse );
}
}
@@ -4194,7 +4193,7 @@ ERR FMP::ErrDBReadPages(
// If we got an unexpected lost flush error, loop for a while to see if the page fixes itself.
if ( ( err == JET_errReadLostFlushVerifyFailure ) && !FNegTest( fCorruptingWithLostFlush ) )
{
- DWORD cRetriesMax = 0;
+ DWORD cRetriesMax = 0, cRetriesToAssert = 0;
#ifdef DEBUG
const CPG cpgActual = pgnoEnd - pgnoStart + 1;
@@ -4205,10 +4204,14 @@ ERR FMP::ErrDBReadPages(
}
cRetriesMax = 100;
+
+ // Unfortunately, there seems to be hardware which loses writes in our test pass pool of machines.
+ cRetriesToAssert = 2;
#else // !DEBUG
// FNegTest() always returns fFalse in RETAIL, so do not run the retry loop when running tests, otherwise
// they will get confused with multiple events and take too long with 1 sec per lost flush detected.
cRetriesMax = ( _wcsicmp( WszUtilProcessName(), L"Microsoft.Exchange.Store.Worker" ) == 0 ) ? 10 : 0;
+ cRetriesToAssert = 1;
#endif // DEBUG
if ( cRetriesMax > 0 )
@@ -4231,7 +4234,7 @@ ERR FMP::ErrDBReadPages(
UtilSleep( 100 );
}
- AssertTrack( fFalse, OSFormat( "UnexpectedLostFlush:%I32u:%d:%d", cRetries, err, errRetry ) );
+ AssertTrack( cRetries < cRetriesToAssert, OSFormat( "UnexpectedLostFlush:%I32u:%d:%d", cRetries, err, errRetry ) );
}
}
@@ -4604,7 +4607,7 @@ ERR ErrBeginDatabaseIncReseedTracing_( _In_ IFileSystemAPI * pfsapi, _In_ JET_PC
// create the tracing file
- CPRINTF * const pcprintfAlloc = new CPRINTFFILE( wszIrsRawFile );
+ CPRINTF * const pcprintfAlloc = new CPRINTFFILE( wszIrsRawFile, CPRINTFFILE::FILEENCODING::ASCII );
Alloc( pcprintfAlloc ); // avoid clobbering the default / NULL tracer
// set tracing to goto the tracing file
@@ -4765,6 +4768,7 @@ ERR CIrsOpContext::ErrCheckAttachedIrsContext( const INST * const pinst, PCWSTR
err = ErrUtilReadShadowedHeader( pinst,
pinst->m_pfsapi,
m_pfapiDb,
+ JET_filetypeDatabase,
(BYTE*)pdbfilehdrCheck,
g_cbPage,
OffsetOf( DBFILEHDR, le_cbPageSize ) );
@@ -4991,6 +4995,7 @@ ERR ErrIRSAttachDatabaseForIrsV2( _Inout_ INST * const pinst, _In_ PCWSTR wszDat
err = ErrUtilReadShadowedHeader( pinst,
pinst->m_pfsapi,
pfapiDb,
+ JET_filetypeDatabase,
(BYTE*)pdbfilehdr,
g_cbPage,
OffsetOf( DBFILEHDR, le_cbPageSize ) );
@@ -5853,6 +5858,7 @@ ERR ErrIsamEndDatabaseIncrementalReseed(
err = ErrUtilReadShadowedHeader( pinst,
pfsapi,
pfapiCheckpoint,
+ JET_filetypeCheckpoint,
(BYTE*)pcheckpoint,
sizeof( CHECKPOINT ),
-1,
@@ -6487,6 +6493,7 @@ ERR ErrIsamRemoveLogfile(
pinstNil,
pfsapi,
wszDatabase,
+ JET_filetypeDatabase,
reinterpret_cast( pdbfilehdr ),
g_cbPage,
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ),
@@ -6896,7 +6903,7 @@ ERR ErrIOReadDbPages(
PGNO pgnoMaxDb = pgnoEnd + 1;
volatile LONG acRead = 0;
- CAutoResetSignal asigDone( CSyncBasicInfo( _T( "ErrIOReadDbPages::asigDone" ) ) );
+ CAutoResetSignal asigDone( CSyncBasicInfo( "ErrIOReadDbPages::asigDone" ) );
READPAGE_DATA readdata;
readdata.err = JET_errSuccess;
diff --git a/dev/ese/src/ese/jetapi.cxx b/dev/ese/src/ese/jetapi.cxx
index 1f694b4c..6772b8e7 100644
--- a/dev/ese/src/ese/jetapi.cxx
+++ b/dev/ese/src/ese/jetapi.cxx
@@ -1549,6 +1549,92 @@ VOID PERFSetDatabaseNames( IFileSystemAPI* const pfsapi )
}
+#ifdef ENABLE_MICROSOFT_MANAGED_DATACENTER_LEVEL_OPTICS
+
+//
+// Trace to an IRS.RAW the init failure.
+//
+
+void DumpFailedInitToIrsRaw(
+ _In_ INST * pinst,
+ _In_ PCWSTR wszInstDisplayName,
+ _In_ PCWSTR wszErrorState,
+ _In_ PCWSTR wszSeconds,
+ _In_ PCWSTR wszFailingMode,
+ _In_ PCWSTR wszFailingAddress,
+ _In_ PCWSTR wszHaPublishingFacts )
+{
+ __int64 fileTime;
+ WCHAR wszDate[32];
+ WCHAR wszTime[32];
+ size_t cchRequired;
+ WCHAR wszInstIrsFile[ 5 /* Inst- */ + 3 /* inst log base name */ + 1 ];
+ WCHAR wszInstIrsPathBase[ OSFSAPI_MAX_PATH ];
+ CPRINTF * pcprintfPageTrace = NULL;
+
+ if ( pinst == NULL || pinst->m_pfsapi == NULL )
+ {
+ FireWall( "InstIrsUnexpectedInitExitBeforeInstOrPfsapiAlloc" );
+ return;
+ }
+
+ if ( ( SzParam( pinst, JET_paramLogFilePath ) == NULL ) ||
+ ( SzParam( pinst, JET_paramLogFilePath )[0] == L'\0' ) )
+ {
+ FireWall( "InstIrsLogPathNotSet" );
+ return;
+ }
+
+ if ( ( SzParam( pinst, JET_paramBaseName ) == NULL ) ||
+ ( SzParam( pinst, JET_paramBaseName )[0] == L'\0' ) )
+ {
+ FireWall( "InstIrsBaseNameNotSet" );
+ return;
+ }
+
+ // make path
+ //
+ OSStrCbFormatW( wszInstIrsFile, sizeof( wszInstIrsFile ), L"Inst-%ws", SzParam( pinst, JET_paramBaseName ) );
+ ERR errT = pinst->m_pfsapi->ErrPathBuild(
+ SzParam( pinst, JET_paramLogFilePath ),
+ wszInstIrsFile,
+ L"", // ext filled by IRS func / ErrBeginDatabaseIncReseedTracing()
+ wszInstIrsPathBase,
+ sizeof( wszInstIrsPathBase ) );
+ if ( errT < JET_errSuccess )
+ {
+ FireWall( "InstIrsPathBuildFail" );
+ return;
+ }
+
+ // start tracing (before anything else)
+ //
+ errT = ErrBeginDatabaseIncReseedTracing( pinst->m_pfsapi, wszInstIrsPathBase, &pcprintfPageTrace );
+ if ( errT < JET_errSuccess )
+ {
+ AssertSzRTL( FRFSAnyFailureDetected(), "InstIrsFailedIrsOpen" );
+ return;
+ }
+
+ fileTime = UtilGetCurrentFileTime();
+ ErrUtilFormatFileTimeAsTimeWithSeconds( fileTime, wszTime, _countof(wszTime), &cchRequired);
+ ErrUtilFormatFileTimeAsDate( fileTime, wszDate, _countof(wszDate), &cchRequired);
+ (*pcprintfPageTrace)( "Begin " __FUNCTION__ "() @ Time %ws %ws\r\n", wszTime, wszDate );
+
+ // Consider adding ERRFormatIssueSource() to get last error information and Server Version.
+ (*pcprintfPageTrace)( "JetInit (%ws) Failed with %ws in %ws seconds.\r\n", wszInstDisplayName, wszErrorState, wszSeconds );
+ (*pcprintfPageTrace)( "Failing Mode: %ws\r\n", wszFailingMode );
+ (*pcprintfPageTrace)( "Failing Address: %ws\r\n", wszFailingAddress );
+ (*pcprintfPageTrace)( "HA Pub Facts: %ws\r\n", wszHaPublishingFacts );
+
+ EndDatabaseIncReseedTracing( &pcprintfPageTrace );
+
+ return;
+}
+
+#endif // ENABLE_MICROSOFT_MANAGED_DATACENTER_LEVEL_OPTICS
+
+
//
// CIsamSequenceDiagLog
//
@@ -1778,6 +1864,9 @@ __int64 CIsamSequenceDiagLog::UsecTimer( _In_ INT seqBegin, _In_ const INT seqEn
return 0;
}
+ Expected( FTriggeredSequence_( 0 ) ); // be odd to have not started sequence and ask for timings
+ Expected( seqEnd + 1 != m_cseqMax || FTriggeredSequence_( seqEnd ) );
+
if ( !FValidSequence_( seqBegin ) ||
!FValidSequence_( seqEnd ) ||
seqBegin >= seqEnd ||
@@ -1793,9 +1882,10 @@ __int64 CIsamSequenceDiagLog::UsecTimer( _In_ INT seqBegin, _In_ const INT seqEn
{
seqBegin--;
}
-
+ Expected( seqBegin < seqEnd ); // this should be true unless we had a failure before the 2nd sequence (seq = 1). Let us see if it happens.
+
if ( !FTriggeredSequence_( seqBegin ) ||
- !FTriggeredSequence_( seqEnd ) )
+ !FTriggeredSequence_( seqEnd ) )
{
return 0;
}
@@ -2622,14 +2712,17 @@ LOCAL const BYTE bProcFriendlyNameAggregationID = 1;
LONG LProcFriendlyNameICFLPwszPpb( _In_ LONG icf, _Inout_opt_ void* const pvParam1, _Inout_opt_ void* const pvParam2 )
{
+ ERR err;
+
switch ( icf )
{
case ICFInit:
{
// Even though we'll truncate the string at cchPerfmonInstanceNameMax,
- // the OSStrCbFormatW() will assert if it truncates the string.
- (void) ErrOSStrCbFormatW( g_wszProcName, sizeof(g_wszProcName), L"%ws\0" , WszUtilProcessFriendlyName() );
-
+ // OSStrCbFormatW() will Assert on anything but JET_errSuccess, and
+ // truncation is not JET_errSuccess.
+ err = ErrOSStrCbFormatW( g_wszProcName, sizeof(g_wszProcName), L"%ws\0" , WszUtilProcessFriendlyName() );
+ Assert( err == JET_errSuccess || err == JET_errBufferTooSmall );
AtomicExchange( &g_lRefreshPerfInstanceList, 1 );
return 1;
@@ -3135,22 +3228,11 @@ class CInstanceFileSystemConfiguration : public CDefaultFileSystemConfiguration
// initialize this setting
if ( m_permillageSmoothIo == dwMax )
{
- // Exs: 999‰ = 99.9% Smooth, 990‰ = 99.0% Smooth, 900‰ = 90.0% Smooth. Debug default = 0.2%
- ULONG permillageSmoothIo = OnDebugOrRetail( 2, CDefaultFileSystemConfiguration::PermillageSmoothIo() );
-
- if ( m_pinst )
- {
- if ( !FDefaultParam( m_pinst, JET_paramFlight_SmoothIoTestPermillage ) )
- {
- permillageSmoothIo = (ULONG)UlParam( m_pinst, JET_paramFlight_SmoothIoTestPermillage );
- }
- }
- Assert( permillageSmoothIo != dwMax );
-
- m_permillageSmoothIo = permillageSmoothIo;
+ // Exs: 999� = 99.9% Smooth, 990� = 99.0% Smooth, 900� = 90.0% Smooth. Debug default = 0.2%
+ m_permillageSmoothIo = OnDebugOrRetail( 2, CDefaultFileSystemConfiguration::PermillageSmoothIo() );
+ Assert( m_permillageSmoothIo != dwMax );
}
- Assert( m_permillageSmoothIo != dwMax );
return m_permillageSmoothIo;
}
@@ -6217,7 +6299,7 @@ SetCacheSizeRange( CJetParam* const pjetparam,
PCWSTR wszParam )
{
ERR err = JET_errSuccess;
-
+
Call( CJetParam::SetInteger( pjetparam, pinst, ppib, ulParam, wszParam ) );
Call( ErrBFConsumeSettings( bfcsCacheSize, ifmpNil ) );
@@ -6225,6 +6307,22 @@ SetCacheSizeRange( CJetParam* const pjetparam,
return err;
}
+ERR
+SetCacheTraceSamplingRatio( CJetParam* const pjetparam,
+ INST* const pinst,
+ PIB* const ppib,
+ const ULONG_PTR ulParam,
+ PCWSTR wszParam )
+{
+ ERR err = JET_errSuccess;
+
+ Call( CJetParam::SetInteger( pjetparam, pinst, ppib, ulParam, wszParam ) );
+ BFICacheTraceSamplingInit( (ULONG)ulParam );
+
+HandleError:
+ return err;
+}
+
ERR
SetCheckpointDepthMax( CJetParam* const pjetparam,
INST* const pinst,
@@ -7507,6 +7605,10 @@ const
#define JET_paramFlight_RBSCleanupEnabledDEFAULT OnDebugOrRetail( fTrue, fFalse )
+#define JET_paramFlight_ContiguousExtentMoveShrinkEnabledDEFAULT OnDebugOrRetail( fTrue, fFalse )
+
+#define JET_paramFlight_UseCngAes256ImplementationDEFAULT OnDebugOrRetail( fTrue, fFalse )
+
// ================================================================
// The following file is auto-generated from sysparam.xml.
// To modify or add parameters, edit sysparam.xml and run gengen.bat.
@@ -9511,7 +9613,15 @@ LOCAL JET_ERR JET_API JetCreateEncryptionKeyEx(
return ErrERRCheck( JET_errInvalidParameter );
}
*pcbActual = cbKey;
- return ErrOSCreateAes256Key( (BYTE*)pvKey, pcbActual );
+ ERR err = ErrOSCreateAes256Key( PARAM_AES256_IMPLEMENTATION, (BYTE*)pvKey, pcbActual );
+#ifdef DEBUG
+ // On debug, verify that key works with the other implementation
+ if ( err >= JET_errSuccess )
+ {
+ CallS( ErrOSEncryptionVerifyKey( OTHER_AES256_IMPLEMENTATION, (BYTE*)pvKey, *pcbActual ) );
+ }
+#endif
+ return err;
}
JET_ERR JET_API JetCreateEncryptionKey(
@@ -12500,7 +12610,7 @@ JET_ERR JET_API JetBeginSessionW(
JET_TRY( opBeginSession, JetBeginSessionExW( instance, psesid, wszUserName, wszPassword ) );
}
-LOCAL JET_ERR JetDupSessionEx( _In_ JET_SESID sesid, _Out_ JET_SESID *psesid )
+LOCAL JET_ERR JetDupSessionEx( _In_ JET_SESID sesid, _In_ JET_GRBIT grbit, _Out_ JET_SESID *psesid )
{
APICALL_SESID apicall( opDupSession );
@@ -12514,17 +12624,50 @@ LOCAL JET_ERR JetDupSessionEx( _In_ JET_SESID sesid, _Out_ JET_SESID *psesid )
if ( apicall.FEnter( sesid ) )
{
- apicall.LeaveAfterCall( ErrIsamBeginSession(
- (JET_INSTANCE)PinstFromSesid( sesid ),
- psesid ) );
+ ERR err;
+ PIB *ppib = (PIB *)sesid;
+ if ( grbit & ~JET_bitDupReadOnlySnapshot )
+ {
+ err = ErrERRCheck( JET_errInvalidGrbit );
+ }
+ else if ( grbit == JET_bitDupReadOnlySnapshot && ppib->Level() == 0 )
+ {
+ err = ErrERRCheck( JET_errNotInTransaction );
+ }
+ else if ( grbit == JET_bitDupReadOnlySnapshot && ( !ppib->FReadOnlyTrx() || ppib->Level() != 1 ) )
+ {
+ err = ErrERRCheck( JET_errIllegalOperation );
+ }
+ else
+ {
+ err = ErrIsamBeginSession( (JET_INSTANCE)PinstFromSesid( sesid ), psesid );
+ if ( err >= JET_errSuccess && grbit == JET_bitDupReadOnlySnapshot )
+ {
+ err = ((PIB *)*psesid)->ErrDupReadOnlyTransaction( ppib );
+ if ( err < 0 )
+ {
+ CallS( ErrIsamEndSession( *psesid, 0 ) );
+ *psesid = JET_sesidNil;
+ }
+ }
+ }
+
+ apicall.LeaveAfterCall( err );
}
return apicall.ErrResult();
}
+
JET_ERR JET_API JetDupSession( _In_ JET_SESID sesid, _Out_ JET_SESID *psesid )
{
JET_VALIDATE_SESID( sesid );
- JET_TRY( opDupSession, JetDupSessionEx( sesid, psesid ) );
+ JET_TRY( opDupSession, JetDupSessionEx( sesid, 0, psesid ) );
+}
+
+JET_ERR JET_API JetDupSession2( _In_ JET_SESID sesid, _In_ JET_GRBIT grbit, _Out_ JET_SESID *psesid )
+{
+ JET_VALIDATE_SESID( sesid );
+ JET_TRY( opDupSession, JetDupSessionEx( sesid, grbit, psesid ) );
}
/*=================================================================
@@ -13016,6 +13159,7 @@ LOCAL JET_ERR JetGetDatabaseFileInfoEx(
pinstNil,
pfsapi,
wszFullDbName,
+ JET_filetypeDatabase,
(BYTE*)pdbfilehdr,
g_cbPage,
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ),
@@ -13142,6 +13286,7 @@ LOCAL JET_ERR JetGetDatabaseFileInfoEx(
Call( ErrUtilReadShadowedHeader( pinstNil,
pfsapi,
wszFullDbName,
+ InfoLevel == JET_DbInfoFileType ? JET_filetypeUnknown : JET_filetypeDatabase,
(BYTE *)pdbfilehdr,
sizeof( DBFILEHDR ),
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ),
@@ -21459,10 +21604,10 @@ LOCAL JET_ERR JetInitEx(
const ULONG cbTimingResourceDataSequence = pinst->m_isdlInit.CbSprintTimings();
WCHAR * wszTimingResourceDataSequence = (WCHAR *)_alloca( cbTimingResourceDataSequence );
pinst->m_isdlInit.SprintTimings( wszTimingResourceDataSequence, cbTimingResourceDataSequence );
- const __int64 secsInit = pinst->m_isdlInit.UsecTimer( eSequenceStart, eInitDone ) / 1000000; // convert to seconds
- WCHAR wszSeconds[16];
+ const double secsInit = (double)pinst->m_isdlInit.UsecTimer( eSequenceStart, eInitDone ) / 1000000.0; // convert to seconds
+ WCHAR wszSeconds[30];
WCHAR wszInstId[16];
- OSStrCbFormatW( wszSeconds, sizeof(wszSeconds), L"%I64d", secsInit );
+ OSStrCbFormatW( wszSeconds, sizeof(wszSeconds), L"%.3f", secsInit );
OSStrCbFormatW( wszInstId, sizeof(wszInstId), L"%d", IpinstFromPinst( pinst ) );
const WCHAR * rgszT[4] = { wszInstId, wszSeconds, wszTimingResourceDataSequence, wszAdditionalFixedData };
@@ -21499,6 +21644,77 @@ LOCAL JET_ERR JetInitEx(
{
const WCHAR* wszInstDisplayName = ( pinst != NULL && pinst->m_wszDisplayName != NULL ? pinst->m_wszDisplayName : L"_unknown_" );
OSDiagTrackInit( wszInstDisplayName, pinst->m_plog->QwSignLogHash(), err );
+
+ // avoiding quick and dirty non-localized insert text on windows
+#ifdef ENABLE_MICROSOFT_MANAGED_DATACENTER_LEVEL_OPTICS
+
+ pinst->m_isdlInit.Trigger( eInitDone );
+ const double secsInit2 = (double)pinst->m_isdlInit.UsecTimer( eSequenceStart, eInitDone ) / 1000000.0; // convert to seconds
+ WCHAR wszSeconds2[30];
+ OSStrCbFormatW( wszSeconds2, sizeof(wszSeconds2), L"%.3f", secsInit2 );
+
+ WCHAR wszErrorState[120];
+ JET_ERRCAT errcatMostSpecific = JET_errcatUnknown;
+ (void)ErrERRLookupErrorCategory( err, &errcatMostSpecific );
+ if ( PefLastThrow() && err == PefLastThrow()->Err() )
+ {
+ PERSISTED // for optics "(JET_errcat: 10)", etc. see Exch \ EseEventCategorized.cs.
+ OSStrCbFormatW( wszErrorState, sizeof(wszErrorState), L"%d (JET_errcat: %d) (src: %hs:%d)", err, errcatMostSpecific, SzSourceFileName( PefLastThrow()->SzFile() ), PefLastThrow()->UlLine() );
+ }
+ else
+ {
+ PERSISTED // for optics "(JET_errcat: 10)", etc. see Exch \ EseEventCategorized.cs.
+ OSStrCbFormatW( wszErrorState, sizeof(wszErrorState), L"%d (JET_errcat: %d)", err, errcatMostSpecific );
+ }
+
+ WCHAR wszFailingMode[2] = { WchReportInstState( pinst ), L'\0' };
+
+ WCHAR wszFailingAddress[60];
+ // The normal way of detecting recovery \ redo via:
+ // plog->FRecovering() && plog->FRecoveringMode() == fRecoveringRedo
+ // is controlled and cleaned up by this point even on an error. However, fortunately
+ // the pinst->m_perfstatusEvent mode is one way during init, and not reset until next
+ // call to JetInit() so we use this method for determining what mode we reached.
+ const BOOL fRedo = pinst->m_perfstatusEvent == perfStatusRecoveryRedo;
+ const BOOL fUndo = pinst->m_perfstatusEvent == perfStatusRecoveryUndo;
+ const BOOL fDo = pinst->m_perfstatusEvent == perfStatusRuntime;
+ // Normal method of getting lpgosRedo (plog->LgposLGLogTipNoLock()) won't work for
+ // the same reason the regular mode computation, computes it wrong above. But the
+ // actual lgpos we want is in m_lgposRedo, so use special function to fetch it.
+ LGPOS lgposFailed = !fUndo ? // just in case, we treat everything besides undo as redo.
+ pinst->m_plog->LgposDiagnosticRedoFailedAddress() :
+ pinst->m_plog->LgposLGLogTipNoLock(); // undo address comes from live lgpos tip.
+ // Can imagine actually sticking other pieces of address in here, like the pgno the LR was
+ // referencing, or even logical descriptions like "DbfilehdrReadErr" or something.
+ OSStrCbFormatW( wszFailingAddress, sizeof( wszFailingAddress ),
+ L"lgpos%hs:%08x:%04x:%04x",
+ fRedo ? "Redo" :
+ ( fUndo ? "Undo" :
+ ( fDo ? "RedoOld" :
+ "Redo-Unconfirmed" ) ),
+ lgposFailed.lGeneration, lgposFailed.isec, lgposFailed.ib );
+
+ WCHAR wszHaPublishingFacts[300];
+ PERSISTED // for optics "Verbose: 1", "FI Tags Published: 0x", and "FiCorruptionTag " / "FiLogLogicallyInconsistent ". see Exch \ EseEventCategorized.cs, Exch \ EseDatabaseMonitoringContext.cs
+ (void)ErrOSStrCbFormatW( wszHaPublishingFacts, sizeof( wszHaPublishingFacts ), L"Verbose: %d, FI Tags Published: 0x%x ( %hs%hs%hs)",
+ !!pinst->m_isdlInit.FTriggeredStep( eInitLogRecoverySilentRedoDone ),
+ pinst->m_grbitHaFailureTags,
+#if defined( USE_HAPUBLISH_API )
+ ( pinst->m_grbitHaFailureTags & bitHaPublishedCorruptionTag ) ? "FiCorruptionTag " : "",
+ ( pinst->m_grbitHaFailureTags & bitHaPublishedIoHardTag ) ? "FiIoHardTag " : "",
+ ( pinst->m_grbitHaFailureTags & bitHaPublishedLogLogicallyInconsistentTag ) ? "FiLogLogicallyInconsistent " : ""
+#else
+ "", "", ""
+#endif
+ );
+
+ const WCHAR * rgszFailT[6] = { wszInstDisplayName, wszErrorState, wszSeconds2, wszFailingMode, wszFailingAddress, wszHaPublishingFacts };
+
+ UtilReportEvent( eventError, GENERAL_CATEGORY, START_INSTANCE_FAILED_ID, _countof( rgszFailT ), rgszFailT, 0, NULL, pinst );
+
+ // Also to avoid event wrap, report failures in JetInit() to .IRS.RAW
+ DumpFailedInitToIrsRaw( pinst, wszInstDisplayName, wszErrorState, wszSeconds2, wszFailingMode, wszFailingAddress, wszHaPublishingFacts );
+#endif
}
// if instance allocated in this function call
@@ -23296,7 +23512,7 @@ JET_ERR ErrTestHookCorruptOfflineFile( const JET_TESTHOOKCORRUPT * const pcorrup
IFileAPI::fmfNone ),
&pfapi ) );
- Call( ErrUtilReadShadowedHeader( pinstNil, pfsapi, pfapi, pbPageImage, g_cbPageMax, OffsetOf( DBFILEHDR_FIX, le_cbPageSize ), urhfNoFailOnPageMismatch ) );
+ Call( ErrUtilReadShadowedHeader( pinstNil, pfsapi, pfapi, JET_filetypeDatabase, pbPageImage, g_cbPageMax, OffsetOf( DBFILEHDR_FIX, le_cbPageSize ), urhfNoFailOnPageMismatch ) );
cbPageSize = ((DBFILEHDR*)pbPageImage)->le_cbPageSize;
Call( pfapi->ErrIORead( *TraceContextScope( iorpDirectAccessUtil ),
@@ -23353,7 +23569,7 @@ JET_ERR ErrTESTHOOKAlterDatabaseFileHeader( const JET_TESTHOOKALTERDBFILEHDR * c
Call( ErrOSFSCreate( g_pfsconfigGlobal, &pfsapi ) );
Call( pfsapi->ErrFileOpen( palterdbfilehdr->szDatabase, IFileAPI::fmfNone, &pfapiDatabase ) );
- Call( ErrUtilReadShadowedHeader( pinstNil, pfsapi, pfapiDatabase, (BYTE*)pdbfilehdr, (DWORD)g_cbPageMax, (LONG)OffsetOf( DBFILEHDR_FIX, le_cbPageSize ), urhfReadOnly|urhfNoFailOnPageMismatch, &cbPageSize, &shs ) );
+ Call( ErrUtilReadShadowedHeader( pinstNil, pfsapi, pfapiDatabase, JET_filetypeDatabase, (BYTE*)pdbfilehdr, (DWORD)g_cbPageMax, (LONG)OffsetOf( DBFILEHDR_FIX, le_cbPageSize ), urhfReadOnly|urhfNoFailOnPageMismatch, &cbPageSize, &shs ) );
Call( CFlushMapForUnattachedDb::ErrGetPersistedFlushMapOrNullObjectIfRuntime( palterdbfilehdr->szDatabase, pdbfilehdr, pinstNil, &pfm ) );
@@ -24456,7 +24672,7 @@ LOCAL JET_ERR JetGetRBSFileInfoEx(
Alloc( prbsfilehdr = (RBSFILEHDR * )PvOSMemoryPageAlloc( sizeof( RBSFILEHDR ), NULL ) );
- Call( ErrUtilReadShadowedHeader( pinstNil, pfsapi, pfapi, (BYTE*) prbsfilehdr, sizeof( RBSFILEHDR ), -1, urhfNoAutoDetectPageSize | urhfReadOnly | urhfNoEventLogging ) );
+ Call( ErrUtilReadShadowedHeader( pinstNil, pfsapi, pfapi, JET_filetypeSnapshot, (BYTE*) prbsfilehdr, sizeof( RBSFILEHDR ), -1, urhfNoAutoDetectPageSize | urhfReadOnly | urhfNoEventLogging ) );
UtilLoadRBSinfomiscFromRBSfilehdr( ( JET_RBSINFOMISC* )pvResult, cbMax, ( RBSFILEHDR* )prbsfilehdr );
break;
diff --git a/dev/ese/src/ese/jettest.cxx b/dev/ese/src/ese/jettest.cxx
index 90948cfc..4868a537 100644
--- a/dev/ese/src/ese/jettest.cxx
+++ b/dev/ese/src/ese/jettest.cxx
@@ -5,7 +5,9 @@
#include "PageSizeClean.hxx"
-#ifdef ENABLE_JET_UNIT_TEST
+#ifndef ENABLE_JET_UNIT_TEST
+#error "File jettest.cxx is only supposed to be referenced / compiled in the unit test .vcxproj file."
+#endif
#include
@@ -537,5 +539,7 @@ void JetTestEnforceSEHException::Cleanup()
s_pThreadExcep = NULL;
}
-#endif // ENABLE_JET_UNIT_TEST
-
+BOOL FInEmbeddedUnitTest()
+{
+ return fTrue;
+}
diff --git a/dev/ese/src/ese/logapi.cxx b/dev/ese/src/ese/logapi.cxx
index 35a86ccd..dced7fdf 100644
--- a/dev/ese/src/ese/logapi.cxx
+++ b/dev/ese/src/ese/logapi.cxx
@@ -1004,7 +1004,7 @@ ERR ErrLGScanCheck(
#endif // !DEBUG
const BOOL fScanCheck2Supported = g_rgfmp[ifmp].FEfvSupported( JET_efvScanCheck2 );
- const BOOL fScanCheck2FlagsSupported = g_rgfmp[ ifmp ].FEfvSupported( JET_efvScanCheck2Flags ) && BoolParam( pinst, JET_paramFlight_EnableScanCheck2Flags );
+ const BOOL fScanCheck2FlagsSupported = g_rgfmp[ ifmp ].FEfvSupported( JET_efvScanCheck2Flags );
const BOOL fScanEnableFDPDelete = g_rgfmp[ ifmp ].FEfvSupported( JET_efvRBSTooSoonDeletes ) && BoolParam( pinst, JET_paramFlight_EnableScanCheckFDPDeleteFlags );
DATA data;
@@ -4869,7 +4869,7 @@ ERR ErrLGExtentFreed( LOG * const plog, const IFMP ifmp, const PGNO pgnoFirst, c
// This is not logged for all free extent operations, only for those related to deleting a whole space tree.
DATA rgdata[1];
- const BOOL fExtentFreed2Supported = g_rgfmp[ ifmp ].FEfvSupported( JET_efvExtentFreed2 ) && BoolParam( PinstFromIfmp( ifmp ), JET_paramFlight_EnableExtentFreed2 );
+ const BOOL fExtentFreed2Supported = g_rgfmp[ ifmp ].FEfvSupported( JET_efvExtentFreed2 );
ERR err = JET_errSuccess;
LREXTENTFREED* const plr = fExtentFreed2Supported ? ( new LREXTENTFREED2() ) : ( new LREXTENTFREED() );
@@ -5169,7 +5169,7 @@ const char * SzLrtyp( LRTYP lrtyp )
ERR ErrLrToLogCsvSimple(
- CWPRINTFFILE * pcwpfCsvOut,
+ CPRINTFFILE * pcpfCsvOutW,
LGPOS lgpos,
const LR *plr,
LOG * plog )
@@ -6853,7 +6853,7 @@ And here was the list of the log file after recovery
szLgposLR, cbLR,
pChangeInfo[i].ulChecksum1, pChangeInfo[i].ulChecksum2 );
OSStrCbAppendW( szLR, sizeof(szLR), rgwchBuf );
- (*pcwpfCsvOut)( L"%s", szLR );
+ (*pcpfCsvOutW)( L"%s", szLR );
}
else if ( pLogRecordsCsvFormats[i] == szLogRecordDatabaseInfo )
{
@@ -6871,7 +6871,7 @@ And here was the list of the log file after recovery
pChangeInfo[i].ulChecksum1, pChangeInfo[i].ulChecksum2,
szLRTyp, pChangeInfo[i].dbid, pChangeInfo[i].szDbPath, rgwchSignBuf );
OSStrCbAppendW( szLR, sizeof(szLR), rgwchBuf );
- (*pcwpfCsvOut)( L"%s", szLR );
+ (*pcpfCsvOutW)( L"%s", szLR );
}
else if ( pLogRecordsCsvFormats[i] == szLogRecordPgChangeInfo )
{
@@ -6883,7 +6883,7 @@ And here was the list of the log file after recovery
szLRTyp, pChangeInfo[i].pgno, pChangeInfo[i].objid, pChangeInfo[i].dbid,
pChangeInfo[i].dbtimePre, pChangeInfo[i].dbtimePost );
OSStrCbAppendW( szLR, sizeof(szLR), rgwchBuf );
- (*pcwpfCsvOut)( L"%s", szLR );
+ (*pcpfCsvOutW)( L"%s", szLR );
}
else if ( pLogRecordsCsvFormats[i] == szLogRecordMiscelLrInfo )
@@ -6895,7 +6895,7 @@ And here was the list of the log file after recovery
pChangeInfo[i].ulChecksum1, pChangeInfo[i].ulChecksum2,
szLRTyp );
OSStrCbAppendW( szLR, sizeof(szLR), rgwchBuf );
- (*pcwpfCsvOut)( L"%s", szLR );
+ (*pcpfCsvOutW)( L"%s", szLR );
}
else if ( pLogRecordsCsvFormats[i] == szLogRecordResizeDatabaseInfo ||
pLogRecordsCsvFormats[i] == szLogRecordTrimDatabaseInfo )
@@ -6907,14 +6907,14 @@ And here was the list of the log file after recovery
pChangeInfo[i].ulChecksum1, pChangeInfo[i].ulChecksum2,
szLRTyp, pChangeInfo[i].dbid );
OSStrCbAppendW( szLR, sizeof(szLR), rgwchBuf );
- (*pcwpfCsvOut)( L"%s", szLR );
+ (*pcpfCsvOutW)( L"%s", szLR );
}
else
{
AssertSz( fFalse, "Unknown CSV type!!!" );
}
- (*pcwpfCsvOut)( L"\r\n" );
+ (*pcpfCsvOutW)( L"\r\n" );
// Only print out size with the first csv line for a log record (to avoid double counting)
cbLR = 0;
}
diff --git a/dev/ese/src/ese/logdiff.cxx b/dev/ese/src/ese/logdiff.cxx
index 75ad61d8..ca77d840 100644
--- a/dev/ese/src/ese/logdiff.cxx
+++ b/dev/ese/src/ese/logdiff.cxx
@@ -1178,13 +1178,15 @@ ERR ErrLGGetAfterImage(
if ( ibOffsetOld < 0 )
{
AssertSz( fFalse, "Buffer underrun detected in ErrLGGetAfterImage: ibOffsetOld < 0" );
- Call( ErrERRCheck( JET_errLogFileCorrupt ) );
+ OSUHAEmitFailureTag( PinstFromIfmp( ifmp ), HaDbFailureTagLogLogicallyInconsistent, L"6d68938e-f163-4a3a-b742-683e6bfbbef1" );
+ Call( ErrERRCheck( JET_errLogCorrupted ) );
}
if ( pbOld + ibOffsetOld < pbOldCur )
{
AssertSz( fFalse, "Buffer underrun detected in ErrLGGetAfterImage, pbOld + ibOffsetOld < pbOldCur" );
- Call( ErrERRCheck( JET_errLogFileCorrupt ) );
+ OSUHAEmitFailureTag( PinstFromIfmp( ifmp ), HaDbFailureTagLogLogicallyInconsistent, L"e6959992-a3c5-4849-9eea-49185cd840c9" );
+ Call( ErrERRCheck( JET_errLogCorrupted ) );
}
cbSkip = pbOld + ibOffsetOld - pbOldCur;
@@ -1192,7 +1194,8 @@ ERR ErrLGGetAfterImage(
(INT_PTR)cbSkip < 0 )
{
AssertSz( fFalse, "Buffer corruption detected in ErrLGGetAfterImage" );
- Call( ErrERRCheck( JET_errLogFileCorrupt ) );
+ OSUHAEmitFailureTag( PinstFromIfmp( ifmp ), HaDbFailureTagLogLogicallyInconsistent, L"0d959afa-737b-4697-933d-8432d92b1ef0" );
+ Call( ErrERRCheck( JET_errLogCorrupted ) );
}
UtilMemCpy( pbNewCur, pbOldCur, cbSkip );
@@ -1214,7 +1217,8 @@ ERR ErrLGGetAfterImage(
cbDataNew < 0)
{
AssertSz( fFalse, "Stack corruption detected in ErrLGGetAfterImage after UtilMemCpy called" );
- Call( ErrERRCheck( JET_errLogFileCorrupt ) );
+ OSUHAEmitFailureTag( PinstFromIfmp( ifmp ), HaDbFailureTagLogLogicallyInconsistent, L"bc55b9ec-ad44-4821-be93-8513e3b6bcf4" );
+ Call( ErrERRCheck( JET_errLogCorrupted ) );
}
if ( diffhdr2.FInsert() )
@@ -1252,12 +1256,14 @@ ERR ErrLGGetAfterImage(
if ( pbDiffCur > pbDiffMax )
{
AssertSz( fFalse, "Buffer overrun detected in ErrLGGetAfterImage, pbDiffCur > pbDiffMax" );
- Call( ErrERRCheck( JET_errLogFileCorrupt ) );
+ OSUHAEmitFailureTag( PinstFromIfmp( ifmp ), HaDbFailureTagLogLogicallyInconsistent, L"91c1d32d-3430-485e-b4c4-ed57145a8460" );
+ Call( ErrERRCheck( JET_errLogCorrupted ) );
}
if ( pbOldCur > pbOld + cbOld )
{
AssertSz( fFalse, "Buffer overrun detected in ErrLGGetAfterImage, pbOldCur > pbOld + cbOld" );
- Call( ErrERRCheck( JET_errLogFileCorrupt ) );
+ OSUHAEmitFailureTag( PinstFromIfmp( ifmp ), HaDbFailureTagLogLogicallyInconsistent, L"bee21012-3b13-4655-9918-7e1d30312bce" );
+ Call( ErrERRCheck( JET_errLogCorrupted ) );
}
}
@@ -1268,7 +1274,8 @@ ERR ErrLGGetAfterImage(
if ( pbNewCur + cbT - pbNew > g_rgfmp[ ifmp ].CbPage() )
{
AssertSz( fFalse, "Buffer overrun detected in ErrLGGetAfterImage: data generated is larger than a page" );
- Call( ErrERRCheck( JET_errLogFileCorrupt ) );
+ OSUHAEmitFailureTag( PinstFromIfmp( ifmp ), HaDbFailureTagLogLogicallyInconsistent, L"b8e53971-65f2-492d-b0a6-07bd404ba4bd" );
+ Call( ErrERRCheck( JET_errLogCorrupted ) );
}
UtilMemCpy( pbNewCur, pbOldCur, cbT );
diff --git a/dev/ese/src/ese/lv.cxx b/dev/ese/src/ese/lv.cxx
index ac45a0a6..d0405048 100644
--- a/dev/ese/src/ese/lv.cxx
+++ b/dev/ese/src/ese/lv.cxx
@@ -3095,7 +3095,7 @@ INLINE ERR ErrLVAppendChunks(
if ( CpgDIRActiveSpaceRequestReserve( pfucbLV ) == cpgDIRReserveConsumed )
{
// yay, we allocated contiguous pages for the LV. Turn off computations of LV reserve required.
- DIRSetActiveSpaceRequestReserve( pfucbLV, 0 );
+ DIRResetActiveSpaceRequestReserve( pfucbLV );
cpgRequiredReserve = 0;
}
@@ -3118,7 +3118,7 @@ INLINE ERR ErrLVAppendChunks(
Assert( CpgDIRActiveSpaceRequestReserve( pfucbLV ) != cpgDIRReserveConsumed );
- DIRSetActiveSpaceRequestReserve( pfucbLV, 0 );
+ DIRResetActiveSpaceRequestReserve( pfucbLV );
return err;
}
@@ -5668,7 +5668,7 @@ ERR ErrRECICreateLvRootAndChunks(
// fits on a page.
*pcpgLvSpaceRequired = 0;
}
- DIRSetActiveSpaceRequestReserve( pfucbLV, 0 );
+ DIRResetActiveSpaceRequestReserve( pfucbLV );
}
Assert( CpgDIRActiveSpaceRequestReserve( pfucbLV ) == 0 );
diff --git a/dev/ese/src/ese/node.cxx b/dev/ese/src/ese/node.cxx
index 9ad48eea..019e4a22 100644
--- a/dev/ese/src/ese/node.cxx
+++ b/dev/ese/src/ese/node.cxx
@@ -2664,7 +2664,7 @@ INT INDIGetReservedTag( _In_ CPAGE& cpage, _In_ NodeResvTagId resvTagId, _Out_ D
INT INDGetReservedTag( _In_ FUCB* pfucb, _In_ CSR* pcsr, _In_ NodeResvTagId resvTagId, _Out_ DATA* pdata )
// ================================================================
{
- Assert( g_rgfmp[ pfucb->ifmp ].ErrDBFormatFeatureEnabled( JET_efvReservedTags ) );
+ Assert( JET_errSuccess == g_rgfmp[ pfucb->ifmp ].ErrDBFormatFeatureEnabled( JET_efvReservedTags ) );
Assert( resvTagId <= rtidMax );
return INDIGetReservedTag( pcsr->Cpage(), resvTagId, pdata );
}
@@ -2699,7 +2699,7 @@ INT INDAddReservedTag( _In_ FUCB* pfucb, _In_ CSR* pcsr, _In_ NodeResvTagId resv
// Caller should log this operation before calling this API.
{
Assert( pcsr->FDirty() );
- Assert( g_rgfmp[ pfucb->ifmp ].ErrDBFormatFeatureEnabled( JET_efvReservedTags ) );
+ Assert( pfucb == NULL || JET_errSuccess == g_rgfmp[ pfucb->ifmp ].ErrDBFormatFeatureEnabled( JET_efvReservedTags ) );
Assert( pcsr->Cpage().CbPageFree() > cb );
Assert( resvTagId <= rtidMax );
@@ -2732,7 +2732,7 @@ VOID NDReplaceReservedTag( _In_ FUCB* pfucb, _In_ CSR* pcsr, _In_ NodeResvTagId
// Caller should log this operation before calling this API.
{
Assert( pcsr->FDirty() );
- Assert( g_rgfmp[ pfucb->ifmp ].ErrDBFormatFeatureEnabled( JET_efvReservedTags ) );
+ Assert( JET_errSuccess == g_rgfmp[ pfucb->ifmp ].ErrDBFormatFeatureEnabled( JET_efvReservedTags ) );
Assert( resvTagId <= rtidMax );
NDIReplaceReservedTag( pcsr->Cpage(), resvTagId, data );
diff --git a/dev/ese/src/ese/old.cxx b/dev/ese/src/ese/old.cxx
index 7d5f86bc..65603a80 100644
--- a/dev/ese/src/ese/old.cxx
+++ b/dev/ese/src/ese/old.cxx
@@ -2043,7 +2043,7 @@ LOCAL ERR ErrOLDDefragOneTree(
err = ErrBTIMultipageCleanup( pfucb, bmStart, &bmNext, preccheck, &mergetype, fTrue );
BTUp( pfucb );
- if ( err < 0 )
+ if ( err < JET_errSuccess )
{
// if out of version store, try once to clean up
if ( ( JET_errVersionStoreOutOfMemory == err || JET_errVersionStoreOutOfMemoryAndCleanupTimedOut == err )
@@ -5323,13 +5323,18 @@ ERR CTableDefragment::ErrPerformOneMerge_( PrereadInfo * const pPrereadInfo )
if ( mergetypeNone == mergetype || mergetypePartialLeft == mergetype )
{
err = ErrBTPageMove( m_pfucbToDefrag, bmCurr, pgnoNull, fTrue, fSPContinuous, &bmNext );
- Call( err );
-
- if ( err != wrnBTShallowTree )
+
+ if ( err >= JET_errSuccess )
{
m_pold2Status->IncrementCpgMoved();
PERFOpt( cOLDPagesMoved.Inc( pinst ) );
}
+ else if ( err == errBTShallowTree )
+ {
+ err = JET_errSuccess;
+ }
+
+ Call( err );
}
m_pold2Status->SetBookmark( bmNext );
diff --git a/dev/ese/src/ese/pib.cxx b/dev/ese/src/ese/pib.cxx
index ff695e26..8a3a6b9e 100644
--- a/dev/ese/src/ese/pib.cxx
+++ b/dev/ese/src/ese/pib.cxx
@@ -271,6 +271,16 @@ VOID PIB::AssertNoDeferredRceid() const
AssertRTL( m_redblacktreeRceidDeferred.FEmpty() );
}
+#ifdef DEBUG
+// ================================================================
+ERR PIB::FDeferredRceid( const RCEID& rceid )
+// ================================================================
+{
+ Assert( rceidNull != rceid );
+ return ( CRedBlackTree::ERR::errSuccess == m_redblacktreeRceidDeferred.ErrFind( rceid ));
+}
+#endif
+
// ================================================================
ERR PIB::ErrRegisterRceid( const RCEID rceid, RCE * const prce)
// ================================================================
@@ -345,6 +355,10 @@ void PIB::DecrementLevel()
m_trxidstack.Pop();
--m_level;
Assert(m_level >= 0);
+ if ( m_level == 0 )
+ {
+ m_fDupedTransaction = fFalse;
+ }
}
// ================================================================
@@ -963,6 +977,39 @@ ERR VTAPI ErrIsamResetSessionContext( JET_SESID sesid )
return JET_errSuccess;
}
+ERR PIB::ErrDupReadOnlyTransaction( PIB *ppibCopyFrom )
+{
+ ERR err = JET_errSuccess;
+ Assert( ppibCopyFrom->FReadOnlyTrx() );
+ Assert( ppibCopyFrom->Level() == 1 );
+ Assert( Level() == 0 );
+
+ // Copy all the user context, like commit-context/cache-priority/tracing-context
+ CallR( ErrSetClientCommitContextGeneric( ppibCopyFrom->PvClientCommitContextGeneric(), ppibCopyFrom->CbClientCommitContextGeneric() ) );
+ m_fCommitContextContainsCustomerData = ppibCopyFrom->m_fCommitContextContainsCustomerData;
+ m_fCommitContextNeedPreCommitCallback = ppibCopyFrom->m_fCommitContextNeedPreCommitCallback;
+ m_pctCachePriority = ppibCopyFrom->m_pctCachePriority;
+ m_grbitUserIoPriority = ppibCopyFrom->m_grbitUserIoPriority;
+ m_qosIoPriority = ppibCopyFrom->m_qosIoPriority;
+ m_utc.DeepCopy( ppibCopyFrom->m_utc );
+ static_assert( JET_sesparamCommitContextNeedPreCommitCallback /* last known */ + 1 == JET_sesparamMaxValueInvalid, "Please make sure you add duping of new sesparam here and update assert" );
+
+ // Now set session context so the new session can be moved if needed to another thread
+ CallS( ErrPIBSetSessionContext( ppibCopyFrom->dwTrxContext ) );
+ PIBSetTrxContext();
+
+ SetFReadOnlyTrx();
+
+ PIBSetTrxBegin0( ppibCopyFrom );
+
+ CallS( ErrLGBeginTransaction( this ) );
+ VERBeginTransaction( this, ppibCopyFrom->m_trxidstack.Peek0() );
+
+ m_fDupedTransaction = fTrue;
+
+ return JET_errSuccess;
+}
+
VOID PIBReportSessionSharingViolation( const PIB * const ppib )
{
WCHAR wszSession[32];
diff --git a/dev/ese/src/ese/rbscleaner_test.cxx b/dev/ese/src/ese/rbscleaner_test.cxx
index f3f4e9be..d2978d09 100644
--- a/dev/ese/src/ese/rbscleaner_test.cxx
+++ b/dev/ese/src/ese/rbscleaner_test.cxx
@@ -47,6 +47,9 @@ class RBSCleanerTestConfig : public IRBSCleanerConfig
QWORD CbMaxSpaceForRBSWhenLowDiskSpace() { return m_cbMaxSpaceForRBSWhenLowDiskSpace; }
VOID SetCbMaxSpaceForRBSWhenLowDiskSpace( QWORD cbMaxSpaceForRBSWhenLowDiskSpace ) { m_cbMaxSpaceForRBSWhenLowDiskSpace = cbMaxSpaceForRBSWhenLowDiskSpace; }
+ QWORD CbMaxSpaceForRBS() { return m_cbMaxSpaceForRBS; }
+ VOID SetCbMaxSpaceForRBS( QWORD cbMaxSpaceForRBS ) { m_cbMaxSpaceForRBS = cbMaxSpaceForRBS; }
+
INT CSecRBSMaxTimeSpan() { return m_cSecRBSMaxTimeSpan; }
VOID SetCSecRBSMaxTimeSpan( INT cSecRBSMaxTimeSpan ) { m_cSecRBSMaxTimeSpan = cSecRBSMaxTimeSpan; }
@@ -62,6 +65,7 @@ class RBSCleanerTestConfig : public IRBSCleanerConfig
m_fEnableCleanup = fTrue;
m_cbLowDiskSpaceThreshold = 1073741824; // 1GB
m_cbMaxSpaceForRBSWhenLowDiskSpace = 1048576; // 1MB
+ m_cbMaxSpaceForRBS = 2147483648; // 2GB, same as disk size by default.
m_cSecRBSMaxTimeSpan = 300; // 5mins
m_cSecMinCleanupIntervalTime = 1; // every 1sec
m_lFirstValidRBSGen = 1;
@@ -74,6 +78,7 @@ class RBSCleanerTestConfig : public IRBSCleanerConfig
QWORD m_cbLowDiskSpaceThreshold;
QWORD m_cbLowDiskSpaceDisableRBSThreshold;
QWORD m_cbMaxSpaceForRBSWhenLowDiskSpace;
+ QWORD m_cbMaxSpaceForRBS;
INT m_cSecRBSMaxTimeSpan;
INT m_cSecMinCleanupIntervalTime;
LONG m_lFirstValidRBSGen;
@@ -853,3 +858,69 @@ JETUNITTEST( RBSCleaner, ExpiredBackupSnapshotsRemoved )
CHECKCALLS( JetTerm2( (JET_INSTANCE) pinst, JET_bitTermAbrupt ) );
}
+
+// Max space of RBS reached and we have to remove multiple RBS files to free up space
+JETUNITTEST( RBSCleaner, MaxRBSSpaceRequiringMultipleRBSRemoval )
+{
+ __int64 ftStartTime = UtilGetCurrentFileTime();
+ unique_ptr pconfig( new RBSCleanerTestConfig() );
+ pconfig->SetCSecRBSMaxTimeSpan( 3600 );
+
+ RBSCleanerTestState* pstate = new RBSCleanerTestState();
+ RBSCleanerTestIOOperator* piooperator = new RBSCleanerTestIOOperator();
+ piooperator->m_lRBSGenMin = 1;
+ piooperator->m_lRBSGenMax = 10;
+
+ // Configure rbs disk space threshold such that we are consuming extra space and multiple RBS snapshots need to be removed.
+ pconfig->SetCbMaxSpaceForRBS( 2 * piooperator->m_cbDirSize );
+
+ INST* pinst;
+ CHECKCALLS( JetCreateInstance2W( (JET_INSTANCE*)&pinst, NULL, NULL, JET_bitNil ) );
+ CHECKCALLS( JetSetSystemParameterW( (JET_INSTANCE*)&pinst, JET_sesidNil, JET_paramEnableRBS, 1, NULL ) );
+
+ unique_ptr prbscleaner( new RBSCleaner( pinst, piooperator, pstate, pconfig.release() ) );
+ CHECK( JET_errSuccess == prbscleaner->ErrStartCleaner() );
+
+ SleepTillConditionSatisfied( pstate->CPassesFinished() == 1, 2, MaxTestRunTimeInMSec );
+
+ CHECK( pstate->FtPassStartTime() >= ftStartTime );
+ CHECK( pstate->FtPrevPassCompletionTime() >= pstate->FtPassStartTime() );
+ CHECK( piooperator->m_cRemoveFolderCalls == 8 );
+ CHECK( piooperator->m_lRBSGenMin == 9 );
+
+ CHECKCALLS( JetTerm2( (JET_INSTANCE)pinst, JET_bitTermAbrupt ) );
+}
+
+// Low disk space but there is space occupied by backup RBS which could be removed. But that's not enough and we need to remove one more RBS.
+JETUNITTEST( RBSCleaner, MaxRBSSpaceBackupRBSRemovalNotEnough )
+{
+ __int64 ftStartTime = UtilGetCurrentFileTime();
+ unique_ptr pconfig( new RBSCleanerTestConfig() );
+ pconfig->SetCSecRBSMaxTimeSpan( 3600 );
+
+ RBSCleanerTestState* pstate = new RBSCleanerTestState();
+ RBSCleanerTestIOOperator* piooperator = new RBSCleanerTestIOOperator();
+ piooperator->m_lRBSGenMin = 1;
+ piooperator->m_lRBSGenMax = 10;
+ piooperator->m_lRBSGenMinBackup = 11;
+ piooperator->m_lRBSGenMaxBackup = 15;
+
+ // Configure rbs disk space threshold such that we are consuming extra space and backup RBS removal alone shouldn't clear up enough space.
+ pconfig->SetCbMaxSpaceForRBS( ( piooperator->m_lRBSGenMax - piooperator->m_lRBSGenMin ) * piooperator->m_cbDirSize );
+
+ INST* pinst;
+ CHECKCALLS( JetCreateInstance2W( (JET_INSTANCE*)&pinst, NULL, NULL, JET_bitNil ) );
+ CHECKCALLS( JetSetSystemParameterW( (JET_INSTANCE*)&pinst, JET_sesidNil, JET_paramEnableRBS, 1, NULL ) );
+
+ unique_ptr prbscleaner( new RBSCleaner( pinst, piooperator, pstate, pconfig.release() ) );
+ CHECK( JET_errSuccess == prbscleaner->ErrStartCleaner() );
+
+ SleepTillConditionSatisfied( pstate->CPassesFinished() == 1, 2, MaxTestRunTimeInMSec );
+
+ CHECK( pstate->FtPassStartTime() >= ftStartTime );
+ CHECK( pstate->FtPrevPassCompletionTime() >= pstate->FtPassStartTime() );
+ CHECK( piooperator->m_cRemoveFolderCalls == 6 );
+ CHECK( piooperator->m_lRBSGenMin == 2 );
+
+ CHECKCALLS( JetTerm2( (JET_INSTANCE)pinst, JET_bitTermAbrupt ) );
+}
diff --git a/dev/ese/src/ese/rbsdump.cxx b/dev/ese/src/ese/rbsdump.cxx
index 4289edc1..ad70d094 100644
--- a/dev/ese/src/ese/rbsdump.cxx
+++ b/dev/ese/src/ese/rbsdump.cxx
@@ -166,6 +166,8 @@ const char* const szEmptyPages2 = "EmptyPg2 ";
const char* const szRootPageMove = "PageMoveR";
+const char* const szRootPageMove2 = "PgMoveR2 ";
+
const char * szRBSRecUnknown = "*UNKNOWN*";
const INT cbRBSRecBuf = 1024 + cbFormattedDataMax;
@@ -182,6 +184,7 @@ const char * SzRBSRec( BYTE bRBSRecType )
case rbsrectypeDbEmptyPages: return szEmptyPages;
case rbsrectypeDbEmptyPages2: return szEmptyPages2;
case rbsrectypeRootPageMove: return szRootPageMove;
+ case rbsrectypeRootPageMove2: return szRootPageMove2;
default: return szRBSRecUnknown;
}
}
@@ -232,7 +235,7 @@ VOID RBSRecToSz( const RBSRecord *prbsrec, __out_bcount(cbRBSRec) PSTR szRBSRec,
dataImage.SetPv( prbsdbpgrec->m_rgbData );
dataImage.SetCb( prbsrec->m_usRecLength - sizeof(RBSDbPageRecord) );
- if ( prbsdbpgrec->m_fFlags )
+ if ( prbsdbpgrec->m_fFlags & ( fRBSPreimageCompressed | fRBSPreimageDehydrated ) )
{
pbDataDecompressed = (BYTE *)PvOSMemoryPageAlloc( g_cbPageFromSnapshot, NULL );
if ( pbDataDecompressed &&
@@ -289,12 +292,14 @@ VOID RBSRecToSz( const RBSRecord *prbsrec, __out_bcount(cbRBSRec) PSTR szRBSRec,
break;
}
case rbsrectypeRootPageMove:
+ case rbsrectypeRootPageMove2:
{
- RBSRootPageMoveRecord* prbsrootpgmoverec = (RBSRootPageMoveRecord*)prbsrec;
- OSStrCbFormatA( rgchBuf, sizeof( rgchBuf ), " [%u:%lu:%lu]",
+ RBSRootPageMove2Record* prbsrootpgmoverec = (RBSRootPageMove2Record*)prbsrec;
+ OSStrCbFormatA( rgchBuf, sizeof( rgchBuf ), " [%u:%lu:%lu], dbtime:%I64x",
(DBID) prbsrootpgmoverec->m_dbid,
(ULONG) prbsrootpgmoverec->m_pgnoSrc,
- (ULONG) prbsrootpgmoverec->m_pgnoDest );
+ (ULONG) prbsrootpgmoverec->m_pgnoDest,
+ (DBTIME) prbsrootpgmoverec->m_dbtime );
OSStrCbAppendA( szRBSRec, cbRBSRec, rgchBuf );
break;
}
@@ -401,6 +406,7 @@ ERR ErrDUMPRBSHeader( INST *pinst, _In_ PCWSTR wszRBS, const BOOL fVerbose )
{
headerRequestPrimaryOnly,
wszRBS,
+ JET_filetypeSnapshot,
NULL,
cbHeader,
-1,
@@ -416,6 +422,7 @@ ERR ErrDUMPRBSHeader( INST *pinst, _In_ PCWSTR wszRBS, const BOOL fVerbose )
{
headerRequestSecondaryOnly,
wszRBS,
+ JET_filetypeSnapshot,
NULL,
cbHeader,
-1,
diff --git a/dev/ese/src/ese/repair.cxx b/dev/ese/src/ese/repair.cxx
index bfebb96f..5f40e69f 100644
--- a/dev/ese/src/ese/repair.cxx
+++ b/dev/ese/src/ese/repair.cxx
@@ -184,7 +184,7 @@ class PgnoCollection : private CArray< PGNO >
{
m_rwl.EnterAsWriter();
- if ( ErrSetEntry( Size(), pgno ) != CArray< PGNO >::ERR::errSuccess )
+ if ( ErrAppendEntry( pgno ) != CArray< PGNO >::ERR::errSuccess )
{
m_rwl.LeaveAsWriter();
return ErrERRCheck( JET_errOutOfMemory );
@@ -265,7 +265,7 @@ struct CHECKTABLE
// need a constructor to initialize the signal
- CHECKTABLE() : signal( CSyncBasicInfo( _T( "CHECKTABLE::signal" ) ) ) {}
+ CHECKTABLE() : signal( CSyncBasicInfo( "CHECKTABLE::signal" ) ) {}
};
@@ -1218,7 +1218,7 @@ ERR ErrDBUTLRepair( JET_SESID sesid, const JET_DBUTIL_W *pdbutil, CPRINTF* const
CallR( ErrERRCheck( JET_errInvalidParameter ) );
}
OSStrCbFormatW(wszFile, sizeof( wszFile ), L"%s%s", wszPrefix, L".INTEG.RAW" );
- CPRINTFFILE cprintfFile( wszFile );
+ CPRINTFFILE cprintfFile( wszFile, CPRINTFFILE::FILEENCODING::ASCII );
// we check this only if we are going to use the szFile in the next line
//
@@ -1231,7 +1231,7 @@ ERR ErrDBUTLRepair( JET_SESID sesid, const JET_DBUTIL_W *pdbutil, CPRINTF* const
OSStrCbFormatW(wszFile, sizeof( wszFile ), L"%s%s", wszPrefix, L".INTGINFO.TXT" );
}
CPRINTF * const pcprintfStatsInternal = ( pdbutil->grbitOptions & JET_bitDBUtilOptionStats ) ?
- new CPRINTFFILE( wszFile ) :
+ new CPRINTFFILE( wszFile, CPRINTFFILE::FILEENCODING::ASCII ) :
CPRINTFNULL::PcprintfInstance();
if ( NULL == pcprintfStatsInternal )
{
@@ -2141,6 +2141,7 @@ LOCAL ERR ErrREPAIRCheckHeader(
err = ErrUtilReadShadowedHeader( pinst,
pinst->m_pfsapi,
wszDatabase,
+ JET_filetypeDatabase,
reinterpret_cast( pdbfilehdr ),
g_cbPage,
OffsetOf( DBFILEHDR_FIX, le_cbPageSize ),
@@ -7166,7 +7167,7 @@ LOCAL ERR ErrREPAIRICheck(
{
if ( !csr.Cpage().FInvisibleSons() )
{
- (*popts->pcprintfError)( "page %d: not an internal page\r\n" );
+ (*popts->pcprintfError)( "page %d: not an internal page\r\n", csr.Pgno() );
Call( ErrERRCheck( JET_errDatabaseCorrupted ) );
}
@@ -8087,6 +8088,7 @@ LOCAL ERR ErrREPAIRChangeDBSignature(
err = ErrUtilReadShadowedHeader( pinst,
pinst->m_pfsapi,
wszDatabase,
+ JET_filetypeDatabase,
reinterpret_cast( pdbfilehdr ),
g_cbPage,
OffsetOf( DBFILEHDR, le_cbPageSize ),
diff --git a/dev/ese/src/ese/revertsnapshot.cxx b/dev/ese/src/ese/revertsnapshot.cxx
index b7cd5aa5..71df6d2d 100644
--- a/dev/ese/src/ese/revertsnapshot.cxx
+++ b/dev/ese/src/ese/revertsnapshot.cxx
@@ -846,7 +846,7 @@ LOCAL ERR ErrRBSLoadRbsGen(
QwInstFileID( qwRBSFileID, pinst->m_iInstance, lRBSGen ),
&pfapiRBS ) );
- err = ErrUtilReadShadowedHeader( pinst, pinst->m_pfsapi, pfapiRBS, (BYTE*) prbshdr, sizeof( RBSFILEHDR ), -1, urhfNoAutoDetectPageSize | urhfNoEventLogging );
+ err = ErrUtilReadShadowedHeader( pinst, pinst->m_pfsapi, pfapiRBS, JET_filetypeSnapshot, (BYTE*) prbshdr, sizeof( RBSFILEHDR ), -1, urhfNoAutoDetectPageSize | urhfNoEventLogging );
if ( fDeleteCorruptUninitializedRBS && err == JET_errReadVerifyFailure )
{
@@ -934,7 +934,7 @@ LOCAL ERR ErrRBSPerformLogChecks(
Call( ErrRBSFilePathForGen_( wszRBSAbsRootDirPath, wszRBSBaseName, pinst->m_pfsapi, wszRBSAbsDirPath, sizeof( wszRBSAbsDirPath ), wszRBSAbsFilePath, cbOSFSAPI_MAX_PATHW, lRBSGen ) );
Call( CIOFilePerf::ErrFileOpen( pinst->m_pfsapi, pinst, wszRBSAbsFilePath, IFileAPI::fmfReadOnly, iofileRBS, qwRBSFileID, &pfapirbs ) );
- Call( ErrUtilReadShadowedHeader( pinst, pinst->m_pfsapi, pfapirbs, (BYTE*) &rbsfilehdr, sizeof( RBSFILEHDR ), -1, urhfNoAutoDetectPageSize | urhfReadOnly | urhfNoEventLogging ) );
+ Call( ErrUtilReadShadowedHeader( pinst, pinst->m_pfsapi, pfapirbs, JET_filetypeSnapshot, (BYTE*) &rbsfilehdr, sizeof( RBSFILEHDR ), -1, urhfNoAutoDetectPageSize | urhfReadOnly | urhfNoEventLogging ) );
Assert( pinst->m_plog );
Assert( rbsfilehdr.rbsfilehdr.le_lGenMaxLogCopied >= rbsfilehdr.rbsfilehdr.le_lGenMinLogCopied );
@@ -1276,7 +1276,7 @@ ERR CRevertSnapshot::ErrSetRBSFileApi( _In_ IFileAPI *pfapiRBS )
Alloc( m_prbsfilehdrCurrent = (RBSFILEHDR *)PvOSMemoryPageAlloc( sizeof(RBSFILEHDR), NULL ) );
// Load the header in the snapshot based on the set file api
- Call( ErrUtilReadShadowedHeader( m_pinst, m_pinst->m_pfsapi, m_pfapiRBS, (BYTE*) m_prbsfilehdrCurrent, sizeof( RBSFILEHDR ), -1, urhfNoAutoDetectPageSize | urhfReadOnly | urhfNoEventLogging ) );
+ Call( ErrUtilReadShadowedHeader( m_pinst, m_pinst->m_pfsapi, m_pfapiRBS, JET_filetypeSnapshot, (BYTE*) m_prbsfilehdrCurrent, sizeof( RBSFILEHDR ), -1, urhfNoAutoDetectPageSize | urhfReadOnly | urhfNoEventLogging ) );
// Set the file time create of current RBS gen on the cleaner.
if ( m_pinst->m_prbscleaner != NULL )
@@ -1873,7 +1873,7 @@ JETUNITTESTDB( RBSPreImageCompression, Xpress, dwOpenDatabase )
#endif // ENABLE_JET_UNIT_TEST
-ERR ErrRBSRDWLatchAndCapturePreImage( _In_ const IFMP ifmp, _In_ const PGNO pgno, _In_ const DBTIME dbtimeLast, ULONG fPreImageFlags, _In_ const BFPriority bfpri, _In_ const TraceContext& tc )
+ERR ErrRBSRDWLatchAndCapturePreImage( _In_ const IFMP ifmp, _In_ const PGNO pgno, _In_ const DBTIME dbtimeLast, ULONG fPreImageFlags, _In_ BOOL fPageFDPDeleteFlagExpected, _In_ const BFPriority bfpri, _In_ const TraceContext& tc )
{
if ( g_rgfmp[ifmp].Dbid() == dbidTemp ||
!g_rgfmp[ifmp].FRBSOn() )
@@ -1883,7 +1883,6 @@ ERR ErrRBSRDWLatchAndCapturePreImage( _In_ const IFMP ifmp, _In_ const PGNO pgno
ERR err = JET_errSuccess;
RBS_POS rbspos;
- CPAGE cpageT;
BFLatch bfl;
// get exclusive latch.
@@ -1899,6 +1898,14 @@ ERR ErrRBSRDWLatchAndCapturePreImage( _In_ const IFMP ifmp, _In_ const PGNO pgno
return JET_errSuccess;
}
+ // If it is expected for the page to have PageFDPDelete flag set but it isn't, return error.
+ // Used during redo to validate any previously deleted and reverted table being redeleted has the flag set.
+ if ( fPageFDPDeleteFlagExpected && !( ( (CPAGE::PGHDR*)bfl.pv )->fFlags & CPAGE::fPageFDPDelete ) )
+ {
+ BFRDWUnlatch( &bfl );
+ return ErrERRCheck( JET_errRBSRedeleteFDPExpected );
+ }
+
Call( g_rgfmp[ifmp].PRBS()->ErrCapturePreimage(
g_rgfmp[ifmp].Dbid(),
pgno,
@@ -2002,18 +2009,19 @@ ERR CRevertSnapshot::ErrCaptureDbAttach( WCHAR* wszDatabaseName, const DBID dbid
return ErrCaptureRec( &dbRec, &dataRec, &dummy );
}
-ERR CRevertSnapshot::ErrCaptureRootPageMove( const DBID dbid, const PGNO pgnoSrc, const PGNO pgnoDest )
+ERR CRevertSnapshot::ErrCaptureRootPageMove( const DBID dbid, const PGNO pgnoSrc, const PGNO pgnoDest, const DBTIME dbtime )
{
RBS_POS dummy;
DATA dataDummy;
dataDummy.Nullify();
- RBSRootPageMoveRecord rootpagemoverec;
- rootpagemoverec.m_bRecType = rbsrectypeRootPageMove;
- rootpagemoverec.m_usRecLength = sizeof( RBSRootPageMoveRecord );
+ RBSRootPageMove2Record rootpagemoverec;
+ rootpagemoverec.m_bRecType = rbsrectypeRootPageMove2;
+ rootpagemoverec.m_usRecLength = sizeof( RBSRootPageMove2Record );
rootpagemoverec.m_dbid = dbid;
rootpagemoverec.m_pgnoSrc = pgnoSrc;
rootpagemoverec.m_pgnoDest = pgnoDest;
+ rootpagemoverec.m_dbtime = dbtime;
return ErrCaptureRec( &rootpagemoverec, &dataDummy, &dummy );
}
@@ -3537,7 +3545,7 @@ ERR RBSCleanerIOOperator::ErrRBSFileHeader( PCWSTR wszRBSFilePath, _Out_ RBSFILE
Assert( pfsapi );
Call( CIOFilePerf::ErrFileOpen( pfsapi, m_pinst, wszRBSFilePath, IFileAPI::fmfReadOnly, iofileRBS, qwRBSFileID, &pfapiRBS ) );
- Call( ErrUtilReadShadowedHeader( m_pinst, pfsapi, pfapiRBS, (BYTE*) prbsfilehdr, sizeof( RBSFILEHDR ), -1, urhfNoAutoDetectPageSize | urhfReadOnly | urhfNoEventLogging ) );
+ Call( ErrUtilReadShadowedHeader( m_pinst, pfsapi, pfapiRBS, JET_filetypeSnapshot, (BYTE*) prbsfilehdr, sizeof( RBSFILEHDR ), -1, urhfNoAutoDetectPageSize | urhfReadOnly | urhfNoEventLogging ) );
HandleError:
if ( pfapiRBS )
@@ -3556,7 +3564,7 @@ RBSCleaner::RBSCleaner(
IRBSCleanerConfig* const prbscleanerconfig ) :
CZeroInit( sizeof( RBSCleaner ) ),
m_pinst( pinst ),
- m_msigRBSCleanerStop( CSyncBasicInfo( _T("RBSCleaner::m_msigRBSCleanerStop" ) ) ),
+ m_msigRBSCleanerStop( CSyncBasicInfo( "RBSCleaner::m_msigRBSCleanerStop" ) ),
m_critRBSFirstValidGen( CLockBasicInfo( CSyncBasicInfo( szRBSFirstValidGen ), rankRBSFirstValidGen, 0 ) ),
m_prbscleaneriooperator( prbscleaneriooperator ),
m_prbscleanerstate( prbscleanerstate ),
@@ -3694,7 +3702,13 @@ ERR RBSCleaner::ErrRBSCleanupBackup( QWORD* cbFreeRBSDisk, QWORD* cbTotalRBSDisk
return JET_errSuccess;
}
- if ( *cbFreeRBSDisk < cbLowDiskSpace && *cbTotalRBSDiskSpace > cbMaxRBSSpaceLowDiskSpace )
+ // We will restrict max space RBS can consume on the disk to avoid overrunning the disk with snapshots.
+ if ( *cbTotalRBSDiskSpace > m_prbscleanerconfig->CbMaxSpaceForRBS() )
+ {
+ fRBSCleanupBackup = fTrue;
+ wszRBSBackupRemoveReason = L"MaxRBSDiskSpace";
+ }
+ else if ( *cbFreeRBSDisk < cbLowDiskSpace && *cbTotalRBSDiskSpace > cbMaxRBSSpaceLowDiskSpace )
{
// Low disk space, lets clean up all the backup snapshots we have for investigation.
fRBSCleanupBackup = fTrue;
@@ -3847,13 +3861,24 @@ ERR RBSCleaner::ErrDoOneCleanupPass()
wszRBSRemoveReason = L"InvalidRBS";
}
- if ( fRBSCleanupMinGen || ( cbFreeRBSDisk < cbLowDiskSpace && cbTotalRBSDiskSpace > cbMaxRBSSpaceLowDiskSpace ) )
+
+ if ( !fRBSCleanupMinGen )
{
- if ( !fRBSCleanupMinGen )
+ // We will restrict max space RBS can consume on the disk to avoid overrunning the disk with snapshots.
+ if ( cbTotalRBSDiskSpace > m_prbscleanerconfig->CbMaxSpaceForRBS() )
{
+ fRBSCleanupMinGen = fTrue;
+ wszRBSRemoveReason = L"MaxRBSDiskSpace";
+ }
+ else if ( cbFreeRBSDisk < cbLowDiskSpace && cbTotalRBSDiskSpace > cbMaxRBSSpaceLowDiskSpace )
+ {
+ fRBSCleanupMinGen = fTrue;
wszRBSRemoveReason = L"LowDiskSpace";
}
+ }
+ if ( fRBSCleanupMinGen )
+ {
Call( m_prbscleaneriooperator->ErrGetDirSize( wszRBSAbsDirPath, &cbRBSDiskSpace ) );
Call( m_prbscleaneriooperator->ErrRemoveFolder( wszRBSAbsDirPath, wszRBSRemoveReason ) );
cbTotalRBSDiskSpace -= cbRBSDiskSpace;
@@ -3960,7 +3985,7 @@ CRBSDatabaseRevertContext::CRBSDatabaseRevertContext( _In_ INST* const pinst )
: CZeroInit( sizeof( CRBSDatabaseRevertContext ) ),
m_pinst ( pinst ),
m_dbidCurrent ( dbidMax ),
- m_asigWritePossible( CSyncBasicInfo( _T( "CRBSDatabaseRevertContext::m_asigWritePossible" ) ) )
+ m_asigWritePossible( CSyncBasicInfo( "CRBSDatabaseRevertContext::m_asigWritePossible" ) )
{
Assert( pinst );
}
@@ -4107,6 +4132,7 @@ ERR CRBSDatabaseRevertContext::ErrRBSDBRCInit( RBSATTACHINFO* prbsattachinfo, SI
m_pinst,
m_pinst->m_pfsapi,
m_pfapiDb,
+ JET_filetypeDatabase,
(BYTE*)m_pdbfilehdr,
g_cbPage,
OffsetOf( DBFILEHDR, le_cbPageSize ) );
@@ -4544,9 +4570,9 @@ ERR CRBSDatabaseRevertContext::ErrAddPage( void* pvPage, PGNO pgno, BOOL fReplac
// Add root page record to the array of records.
//
-ERR CRBSDatabaseRevertContext::ErrAddRootPageRecord( BOOL fDeleteOperation, PGNO pgnoSrc, PGNO pgnoDest )
+ERR CRBSDatabaseRevertContext::ErrAddRootPageRecord( const BOOL fDeleteOperation, const PGNO pgnoSrc, const PGNO pgnoDest, const DBTIME dbtime )
{
- CRootPageRecord rootpagerec( fDeleteOperation, pgnoSrc, pgnoDest );
+ CRootPageRecord rootpagerec( fDeleteOperation, pgnoSrc, pgnoDest, dbtime );
CArray< CRootPageRecord >::ERR errArray = CArray< CRootPageRecord >::ERR::errSuccess;
@@ -4555,7 +4581,11 @@ ERR CRBSDatabaseRevertContext::ErrAddRootPageRecord( BOOL fDeleteOperation, PGNO
m_rgrootpagerec = new CArray< CRootPageRecord >( 32 );
}
- errArray = m_rgrootpagerec->ErrSetEntry( m_rgrootpagerec->Size(), rootpagerec );
+ // Only add entry to root page records if it doesn't exist already
+ if ( m_rgrootpagerec->SearchLinear( rootpagerec, CRBSDatabaseRevertContext::ICRBSDatabaseRootPageRecordEquals ) == CArray< CRootPageRecord >::iEntryNotFound )
+ {
+ errArray = m_rgrootpagerec->ErrAppendEntry( rootpagerec );
+ }
if ( errArray != CArray< CRootPageRecord >::ERR::errSuccess )
{
@@ -4621,7 +4651,7 @@ ERR CRBSDatabaseRevertContext::ErrCapturePageFDPDeleteState( const LONG lRBSGen,
Call( ErrDBDiskPageFDPRootDelete( NULL, m_rgrootpagerec->Entry( i ).PgnoDest(), fTrue, fFalse, cbDbPageSize, &fPgnoFDPRootDelete));
CPageFDPDeleteState pagefdpdeletestate( m_rgrootpagerec->Entry( i ).PgnoDest(), fPgnoFDPRootDelete);
- errArray = rgpagefdpdeletestate->ErrSetEntry( rgpagefdpdeletestate->Size(), pagefdpdeletestate );
+ errArray = rgpagefdpdeletestate->ErrAppendEntry( pagefdpdeletestate );
if ( errArray != CArray< CPageFDPDeleteState >::ERR::errSuccess )
{
@@ -4756,7 +4786,7 @@ ERR CRBSDatabaseRevertContext::ErrRBSInitRootPageDeleteState( const LONG lRBSGen
QWORD cbOffset = 0;
QWORD cbRemaining = cbSize;
- pbread = (BYTE*)PvOSMemoryPageAlloc( cbSize, NULL );
+ pbread = (BYTE*)PvOSMemoryPageAlloc( (size_t)cbSize, NULL );
Alloc( pbread );
while ( cbRemaining > 0 )
@@ -4961,14 +4991,10 @@ ERR CRBSDatabaseRevertContext::ErrRBSApplyRootPageRecords( const USHORT cbDbPage
VOID CRBSDatabaseRevertContext::ResetRootPageRecords()
{
- CArray< CRootPageRecord >::ERR errArray = CArray< CRootPageRecord >::ERR::errSuccess;
-
if ( m_rgrootpagerec != NULL )
{
- errArray = m_rgrootpagerec->ErrSetSize( 0 );
+ m_rgrootpagerec->Clear();
}
-
- Assert( errArray == CArray< CRootPageRecord >::ERR::errSuccess );
}
// Comparer to allow sorting of pages in our array to try and get sequential writes.
@@ -4995,6 +5021,20 @@ INLINE INT __cdecl CRBSDatabaseRevertContext::ICRBSDatabaseRevertContextPgEquals
return ( ( ppg1->PgNo() == ppg2->PgNo() ) ? 0 : ( ( ppg1->PgNo() < ppg2->PgNo() ) ? -1 : +1 ) );
}
+// Equals method to say if both root page records are the same or not.
+//
+INLINE INT __cdecl CRBSDatabaseRevertContext::ICRBSDatabaseRootPageRecordEquals( const CRootPageRecord* prootpagerecord1, const CRootPageRecord* prootpagerecord2 )
+{
+ Assert( prootpagerecord1 );
+ Assert( prootpagerecord2 );
+
+ return ( (
+ prootpagerecord1->PgnoSrc() == prootpagerecord2->PgnoSrc() &&
+ prootpagerecord1->PgnoDest() == prootpagerecord2->PgnoDest() &&
+ prootpagerecord1->FDeleteOperation() == prootpagerecord2->FDeleteOperation() &&
+ prootpagerecord1->Dbtime() == prootpagerecord2->Dbtime() ) ? 0 : 1 );
+}
+
void CRBSDatabaseRevertContext::OsWriteIoComplete(
const ERR errIo,
IFileAPI* const pfapi,
@@ -5137,13 +5177,7 @@ ERR CRBSDatabaseRevertContext::ErrFlushDBPages( USHORT cbDbPageSize, BOOL fFlush
}
}
- errArray = m_rgRBSDbPage->ErrSetSize( 0 );
-
- if ( errArray != CArray< CPagePointer >::ERR::errSuccess )
- {
- Assert( errArray == CArray< CPagePointer >::ERR::errOutOfMemory );
- Error( ErrERRCheck( JET_errOutOfMemory ) );
- }
+ m_rgRBSDbPage->Clear();
// This will be NULL if there is no .jfm file.
if ( m_pfm )
@@ -5310,7 +5344,7 @@ ERR CRBSRevertContext::ErrBeginRevertTracing( bool fDeleteOldTraceFile )
}
// create the tracing file
- CPRINTF * const pcprintfAlloc = new CPRINTFFILE( wszRBSRCRawFile );
+ CPRINTF * const pcprintfAlloc = new CPRINTFFILE( wszRBSRCRawFile, CPRINTFFILE::FILEENCODING::ASCII );
Alloc( pcprintfAlloc ); // avoid clobbering the default / NULL tracer
// set tracing to goto the tracing file
@@ -5385,7 +5419,7 @@ ERR CRBSRevertContext::ErrRevertCheckpointInit()
qwRBSRevertChkFileID,
&m_pfapirbsrchk ) );
- err = ErrUtilReadShadowedHeader( m_pinst, pfsapi, m_pfapirbsrchk, (BYTE*) m_prbsrchk, sizeof( RBSREVERTCHECKPOINT ), -1, urhfNoAutoDetectPageSize );
+ err = ErrUtilReadShadowedHeader( m_pinst, pfsapi, m_pfapirbsrchk, JET_filetypeRBSRevertCheckpoint, (BYTE*) m_prbsrchk, sizeof( RBSREVERTCHECKPOINT ), -1, urhfNoAutoDetectPageSize );
if ( err < JET_errSuccess )
{
@@ -5899,13 +5933,13 @@ ERR CRBSRevertContext::ErrAddRevertedNewPage( DBID dbid, PGNO pgnoRevertNew, con
// Add root page record to the array of records for the given database.
//
-ERR CRBSRevertContext::ErrAddRootPageRecord( DBID dbid, BOOL fDeleteOperation, PGNO pgnoSrc, PGNO pgnoDest )
+ERR CRBSRevertContext::ErrAddRootPageRecord( const DBID dbid, const BOOL fDeleteOperation, const PGNO pgnoSrc, const PGNO pgnoDest, const DBTIME dbtime )
{
Assert( m_mpdbidirbsdbrc[ dbid ] != irbsdbrcInvalid );
Assert( m_mpdbidirbsdbrc[ dbid ] <= m_irbsdbrcMaxInUse );
Assert( m_rgprbsdbrcAttached[ m_mpdbidirbsdbrc[ dbid ] ] );
- return m_rgprbsdbrcAttached[ m_mpdbidirbsdbrc[ dbid ] ]->ErrAddRootPageRecord( fDeleteOperation, pgnoSrc, pgnoDest );
+ return m_rgprbsdbrcAttached[ m_mpdbidirbsdbrc[ dbid ] ]->ErrAddRootPageRecord( fDeleteOperation, pgnoSrc, pgnoDest, dbtime );
}
// Checks whether we continue applying RBS, taking any required actions.
@@ -6046,27 +6080,18 @@ ERR CRBSRevertContext::ErrApplyRBSRecord( RBSRecord* prbsrec, BOOL fCaptureDbHdr
// At the end of the snapshot, we will go through and apply the flag while going through the records in the reverse order.
// We need to do this in reverse order since we allow shrink/table creation to happen in the snapshot window.
// So we might have to move the flag from one root page to another.
- if ( prbsdbpgrec->m_fFlags & fRBSDeletedTableRootPage && fRevertStateRootPageRecords )
- {
- Call( ErrAddRootPageRecord( prbsdbpgrec->m_dbid, fTrue, prbsdbpgrec->m_pgno, pgnoNull ) );
- }
-
- // When we are starting snapshot in JET_revertstateRootPageRecords, all we need is to capture the fact that root page record needs to be marked with FDPDeleteFlag and
- // the fact that we saw a preimage for this page so that root page move record can decide if it needs to be applied.
- // All the preimage applying work should have already been completed.
- if ( fRevertStateRootPageRecords )
- {
- SetPageCaptured( prbsdbpgrec->m_dbid, prbsdbpgrec->m_pgno );
- return JET_errSuccess;
- }
+ BOOL fAddRootPageRecord = prbsdbpgrec->m_fFlags & fRBSDeletedTableRootPage && fRevertStateRootPageRecords;
// If either revert always flag is set or if we have not already captured page preimage to revert to, capture the page record.
- if ( prbsdbpgrec->m_fFlags & fRBSPreimageRevertAlways || !fPageAlreadyCaptured )
+ BOOL fAddDbPageRecord = ( prbsdbpgrec->m_fFlags & fRBSPreimageRevertAlways || !fPageAlreadyCaptured ) && !fRevertStateRootPageRecords;
+
+
+ if ( fAddDbPageRecord || fAddRootPageRecord )
{
pvPage = PvOSMemoryPageAlloc( m_cbDbPageSize, NULL );
Alloc( pvPage );
- if ( prbsdbpgrec->m_fFlags )
+ if ( prbsdbpgrec->m_fFlags & ( fRBSPreimageCompressed | fRBSPreimageDehydrated ) )
{
Call( ErrRBSDecompressPreimage( dataImage, m_cbDbPageSize, (BYTE*) pvPage, prbsdbpgrec->m_pgno, prbsdbpgrec->m_fFlags ) );
}
@@ -6080,15 +6105,36 @@ ERR CRBSRevertContext::ErrApplyRBSRecord( RBSRecord* prbsrec, BOOL fCaptureDbHdr
CPAGE cpage;
cpage.LoadPage( ifmpNil, prbsdbpgrec->m_pgno, pvPage, m_cbDbPageSize );
- cpage.PreparePageForWrite( CPAGE::PageFlushType::pgftUnknown, fTrue, fTrue );
- // We will check the root page for fPageFDPDelete, if it is a root page and fPageFDPDelete is not set on the preimage and
- // no other preimage was captured as part of this snapshot. If one was captured, we should have done the check for fPageFDPDelete then.
- fCheckPageFDPRootDelete = cpage.FRootPage() && !cpage.FPageFDPDelete() && !fPageAlreadyCaptured;
+ if ( fAddRootPageRecord )
+ {
+ Call( ErrAddRootPageRecord( prbsdbpgrec->m_dbid, fTrue, prbsdbpgrec->m_pgno, pgnoNull, cpage.Dbtime() ) );
+ cpage.UnloadPage();
+ OSMemoryPageFree( pvPage );
+ pvPage = NULL;
+ }
+ else
+ {
+ Assert( fAddDbPageRecord );
+ cpage.PreparePageForWrite( CPAGE::PageFlushType::pgftUnknown, fTrue, fTrue );
+
+ // We will check the root page for fPageFDPDelete, if it is a root page and fPageFDPDelete is not set on the preimage and
+ // no other preimage was captured as part of this snapshot. If one was captured, we should have done the check for fPageFDPDelete then.
+ fCheckPageFDPRootDelete = cpage.FRootPage() && !cpage.FPageFDPDelete() && !fPageAlreadyCaptured;
- cpage.UnloadPage();
+ cpage.UnloadPage();
+
+ Call( ErrAddPageRecord( pvPage, prbsdbpgrec->m_dbid, prbsdbpgrec->m_pgno, fPageAlreadyCaptured, fCheckPageFDPRootDelete, fFalse, fFalse, m_cbDbPageSize ) );
+ }
+ }
- Call( ErrAddPageRecord( pvPage, prbsdbpgrec->m_dbid, prbsdbpgrec->m_pgno, fPageAlreadyCaptured, fCheckPageFDPRootDelete, fFalse, fFalse, m_cbDbPageSize ) );
+ // When we are starting snapshot in JET_revertstateRootPageRecords, all we need is to capture the fact that root page record needs to be marked with FDPDeleteFlag and
+ // the fact that we saw a preimage for this page so that root page move record can decide if it needs to be applied.
+ // All the preimage applying work should have already been completed.
+ if ( fRevertStateRootPageRecords )
+ {
+ SetPageCaptured( prbsdbpgrec->m_dbid, prbsdbpgrec->m_pgno );
+ return JET_errSuccess;
}
break;
@@ -6131,8 +6177,9 @@ ERR CRBSRevertContext::ErrApplyRBSRecord( RBSRecord* prbsrec, BOOL fCaptureDbHdr
}
case rbsrectypeRootPageMove:
+ case rbsrectypeRootPageMove2:
{
- RBSRootPageMoveRecord* prbsrootpagemoverec = (RBSRootPageMoveRecord*)prbsrec;
+ RBSRootPageMove2Record* prbsrootpagemoverec = (RBSRootPageMove2Record*)prbsrec;
// We will apply root page record only if we have captured a preimage for the source and destination page.
// RootPageMove record is captured whenever shrink does a root page move or when a table is just created (in this case pgnoSrc = 0).
@@ -6146,7 +6193,7 @@ ERR CRBSRevertContext::ErrApplyRBSRecord( RBSRecord* prbsrec, BOOL fCaptureDbHdr
if ( ( prbsrootpagemoverec->m_pgnoSrc == 0 || FPageAlreadyCaptured( prbsrootpagemoverec->m_dbid, prbsrootpagemoverec->m_pgnoSrc ) ) &&
FPageAlreadyCaptured( prbsrootpagemoverec->m_dbid, prbsrootpagemoverec->m_pgnoDest ) )
{
- Call( ErrAddRootPageRecord( prbsrootpagemoverec->m_dbid, fFalse, prbsrootpagemoverec->m_pgnoSrc, prbsrootpagemoverec->m_pgnoDest ) );
+ Call( ErrAddRootPageRecord( prbsrootpagemoverec->m_dbid, fFalse, prbsrootpagemoverec->m_pgnoSrc, prbsrootpagemoverec->m_pgnoDest, prbsrootpagemoverec->m_dbtime ) );
}
break;
diff --git a/dev/ese/src/ese/space.cxx b/dev/ese/src/ese/space.cxx
index 9be172d1..4b7d5210 100644
--- a/dev/ese/src/ese/space.cxx
+++ b/dev/ese/src/ese/space.cxx
@@ -309,6 +309,12 @@ const CHAR * SzSpaceTreeType( const FUCB * const pfucb )
//
class CSPExtentInfo;
+LOCAL ERR ErrSPIFindExtOE(
+ __inout PIB * ppib,
+ _In_ FCB * pfcb,
+ _In_ const PGNO pgnoFirst,
+ _Out_ CSPExtentInfo * pcspoext );
+
LOCAL ERR ErrSPIAddFreedExtent(
FUCB *pfucb,
FUCB *pfucbAE,
@@ -334,7 +340,6 @@ LOCAL ERR ErrSPIGetFsSe(
FUCB * const pfucbAE,
const CPG cpgReq,
const CPG cpgMin,
- const ULONG fSPFlags,
const BOOL fExact = fFalse,
const BOOL fPermitAsyncExtension = fTrue,
const BOOL fMayViolateMaxSize = fFalse );
@@ -377,17 +382,6 @@ LOCAL ERR ErrSPIUnshelvePagesInRange(
const PGNO pgnoFirst,
const PGNO pgnoLast );
-LOCAL ERR ErrSPIGetInfo(
- FUCB *pfucb,
- CPG *pcpgTotal,
- CPG *pcpgReserved,
- CPG *pcpgShelved,
- INT *piext,
- INT cext,
- EXTENTINFO *rgext,
- INT *pcextSentinelsRemaining,
- CPRINTF * const pcprintf );
-
#ifdef EXPENSIVE_INLINE_EXTENT_PAGE_COUNT_CACHE_VALIDATION
// This function does very expensive validation of the value in the Extent Page
// Count Cache by counting space tree pages inline with other space operations.
@@ -1950,7 +1944,7 @@ class CSPExtentNodeKDF {
class CSPExtentInfo;
- ERR ErrConsumeSpace( _In_ const PGNO pgnoConsume, _In_ const CPG cpgConsume = 1 )
+ ERR ErrConsumeSpace( _In_ const PGNO pgnoConsume, _In_ const CPG cpgConsume, _In_ const BOOL fDeleteInsertionMarker )
{
ASSERT_VALID( this );
@@ -1970,8 +1964,9 @@ class CSPExtentNodeKDF {
Assert( m_spextkey.FValid( m_eSpExtType, SPEXTKEY::fValidateData ) );
- if ( m_spextkey.SppPool() != spp::ContinuousPool &&
- CpgExtent() == 0 )
+ // Leave insertion marker behind for continuous pools, except if we were working
+ // with explicit reservation.
+ if ( ( CpgExtent() == 0 ) && ( ( m_spextkey.SppPool() != spp::ContinuousPool ) || fDeleteInsertionMarker ) )
{
m_fShouldDeleteNode = fTrue;
}
@@ -2411,6 +2406,37 @@ ERR ErrSPGetLastExtent( _Inout_ PIB * ppib, _In_ const IFMP ifmp, _Out_ EXTENTIN
}
+// Gets the FUCB-level extent that owns a specific pgno.
+// Assumes that the caller guarantees that the page is known to be owned
+// by the FUCB provided.
+//
+ERR ErrSPGetOwningExtent( _In_ FUCB * pfucb, _In_ const PGNO pgno, _Out_ EXTENTINFO * pextinfo )
+{
+ ERR err = JET_errSuccess;
+
+ Assert( pfucbNil != pfucb );
+ Assert( !FSPIIsSmall( pfucb->u.pfcb ) );
+ Assert( pfucb->u.pfcb->FSpaceInitialized() );
+ Assert( pfucb->u.pfcb->PgnoOE() != pgnoNull );
+
+ CSPExtentInfo speiOE;
+ err = ErrSPIFindExtOE( pfucb->ppib, pfucb->u.pfcb, pgno, &speiOE );
+ if ( ( err == JET_errNoCurrentRecord ) || ( err == JET_errRecordNotFound ) ||
+ ( ( err >= JET_errSuccess ) && ( !speiOE.FIsSet() || !speiOE.FContains( pgno ) || ( speiOE.CpgExtent() <= 0 ) ) ) )
+ {
+ FireWall( "GetOwningExtNoOwned" );
+ Error( ErrERRCheck( JET_errSPOwnExtCorrupted ) );
+ }
+ Call( err );
+
+ pextinfo->pgnoLastInExtent = speiOE.PgnoLast();
+ pextinfo->cpgExtent = speiOE.CpgExtent();
+
+HandleError:
+ return err;
+}
+
+
// Validate I have not unintentionally changed SPACE_HEADER size.
C_ASSERT( sizeof(SPACE_HEADER) == 16 );
@@ -2567,7 +2593,7 @@ INLINE const SPACE_HEADER * PsphSPIRootPage( FUCB* pfucb )
// get pgnoFDP of parentFDP of this tree
//
-PGNO PgnoSPIParentFDP( FUCB *pfucb )
+PGNO PgnoSPParentFDP( FUCB *pfucb )
{
return PsphSPIRootPage( pfucb )->PgnoParent();
}
@@ -3470,7 +3496,7 @@ ERR ErrSPCreate(
// and if the database is reverted, delete flag can be cleared accordingly.
if ( g_rgfmp[ pfucb->ifmp ].FRBSOn() )
{
- Call( g_rgfmp[ pfucb->ifmp ].PRBS()->ErrCaptureRootPageMove( g_rgfmp[ pfucb->ifmp ].Dbid(), 0, pgnoFDP ) );
+ Call( g_rgfmp[ pfucb->ifmp ].PRBS()->ErrCaptureRootPageMove( g_rgfmp[ pfucb->ifmp ].Dbid(), 0, pgnoFDP, g_rgfmp[ pfucb->ifmp ].DbtimeLast() ) );
}
Assert( !FFUCBSpace( pfucb ) );
@@ -4418,10 +4444,10 @@ VOID SPFreeSpaceCatCtx( _Inout_ SpaceCatCtx** const ppSpCatCtx )
pSpCatCtx->pfucbParent = pfucbNil;
pSpCatCtx->pfucb = pfucbNil;
- if ( pSpCatCtx->pbm != NULL )
+ if ( pSpCatCtx->pbmb != NULL )
{
- delete pSpCatCtx->pbm;
- pSpCatCtx->pbm = NULL;
+ delete pSpCatCtx->pbmb;
+ pSpCatCtx->pbmb = NULL;
}
delete pSpCatCtx;
@@ -4480,7 +4506,7 @@ ERR ErrSPIGetSpaceCategoryObject(
BOOL fPageLatched = fFalse;
KEYDATAFLAGS kdf;
SpaceCatCtx* pSpCatCtx = NULL;
- BOOKMARK_COPY* pbm = NULL;
+ BOOKMARK_BUFFER* pbmb = NULL;
Assert( objid != objidNil );
Assert( objid != objidParent );
@@ -4498,7 +4524,7 @@ ERR ErrSPIGetSpaceCategoryObject(
*ppSpCatCtx = NULL;
Alloc( pSpCatCtx = new SpaceCatCtx );
- Alloc( pbm = new BOOKMARK_COPY );
+ Alloc( pbmb = new BOOKMARK_BUFFER );
// First, determine the pgnoFDP and initialize cursors.
//
@@ -4817,7 +4843,7 @@ ERR ErrSPIGetSpaceCategoryObject(
goto HandleError;
}
- Call( pbm->ErrCopyKeyData( kdf.key, kdf.data ) );
+ Call( pbmb->ErrAllocAndCopyKeyData( kdf.key, kdf.data ) );
}
else
{
@@ -4834,7 +4860,7 @@ ERR ErrSPIGetSpaceCategoryObject(
goto HandleError;
}
- Call( pbm->ErrCopyKey( kdf.key ) );
+ Call( pbmb->ErrAllocAndCopyKey( kdf.key ) );
}
// Release latch before navigating.
@@ -4854,7 +4880,7 @@ ERR ErrSPIGetSpaceCategoryObject(
}
// Try the tree itself.
- err = ErrBTContainsPage( pfucb, *pbm, pgno, fLeafPage );
+ err = ErrBTContainsPage( pfucb, pbmb->Bm(), pgno, fLeafPage);
if ( err >= JET_errSuccess )
{
spcatf |= ( fLeafPage ? spcatfStrictlyLeaf : spcatfStrictlyInternal );
@@ -4877,7 +4903,7 @@ ERR ErrSPIGetSpaceCategoryObject(
spcatf = spcatfInconsistent;
goto HandleError;
}
- err = ErrBTContainsPage( pfucbSpace, *pbm, pgno, fLeafPage );
+ err = ErrBTContainsPage( pfucbSpace, pbmb->Bm(), pgno, fLeafPage);
if ( err >= JET_errSuccess )
{
spcatf |= ( spcatfSpaceAE | ( fLeafPage ? spcatfStrictlyLeaf : spcatfStrictlyInternal ) );
@@ -4901,7 +4927,7 @@ ERR ErrSPIGetSpaceCategoryObject(
spcatf = spcatfInconsistent;
goto HandleError;
}
- err = ErrBTContainsPage( pfucbSpace, *pbm, pgno, fLeafPage );
+ err = ErrBTContainsPage( pfucbSpace, pbmb->Bm(), pgno, fLeafPage);
if ( err >= JET_errSuccess )
{
spcatf |= ( spcatfSpaceOE | ( fLeafPage ? spcatfStrictlyLeaf : spcatfStrictlyInternal ) );
@@ -4974,10 +5000,10 @@ ERR ErrSPIGetSpaceCategoryObject(
if ( ( err >= JET_errSuccess ) &&
!FSPSpaceCatStrictlyInternal( spcatf ) &&
!FSPSpaceCatStrictlyLeaf( spcatf ) &&
- ( pbm != NULL ) )
+ ( pbmb != NULL ) )
{
- delete pbm;
- pbm = NULL;
+ delete pbmb;
+ pbmb = NULL;
}
// Fill out the context struct, either to clean it up or return it.
@@ -4986,14 +5012,14 @@ ERR ErrSPIGetSpaceCategoryObject(
pSpCatCtx->pfucbParent = pfucbParent;
pSpCatCtx->pfucb = pfucb;
pSpCatCtx->pfucbSpace = pfucbSpace;
- pSpCatCtx->pbm = pbm;
+ pSpCatCtx->pbmb = pbmb;
}
else
{
Assert( pfucbParent == pfucbNil );
Assert( pfucb == pfucbNil );
Assert( pfucbSpace == pfucbNil );
- Assert( pbm == NULL );
+ Assert( pbmb == NULL );
}
if ( err >= JET_errSuccess )
@@ -5544,7 +5570,7 @@ ERR ErrSPGetSpaceCategory(
}
// We must have a bookmark if this is an internal or leaf page.
- Assert( !FSPSpaceCatStrictlyInternal( spcatf ) && !FSPSpaceCatStrictlyLeaf( spcatf ) || ( pSpCatCtx->pbm != NULL ) );
+ Assert( !FSPSpaceCatStrictlyInternal( spcatf ) && !FSPSpaceCatStrictlyLeaf( spcatf ) || ( pSpCatCtx->pbmb != NULL ) );
}
else
{
@@ -6157,7 +6183,6 @@ LOCAL ERR ErrSPIGetExt(
pfucbAE,
*pcpgReq,
cpgMin,
- fSPFlags & ( fSPSplitting | fSPExactExtent ),
fFalse, // fExact
fTrue, // fPermitAsyncExtension
fMayViolateMaxSize ) );
@@ -6238,7 +6263,7 @@ LOCAL ERR ErrSPIGetExt(
CSPExtentNodeKDF spAdjustedSize( SPEXTKEY::fSPExtentTypeAE, cspaei.PgnoLast(), cspaei.CpgExtent(), spp::AvailExtLegacyGeneralPool );
OnDebug( const PGNO pgnoLastBefore = cspaei.PgnoLast() );
- Call( spAdjustedSize.ErrConsumeSpace( *ppgnoFirst, *pcpgReq ) );
+ Call( spAdjustedSize.ErrConsumeSpace( *ppgnoFirst, *pcpgReq, fFalse /* fDeleteInsertionMarker */ ) );
Assert( spAdjustedSize.CpgExtent() > 0 );
Assert( pgnoLastBefore == cspaei.PgnoLast() );
@@ -6687,7 +6712,6 @@ ERR ErrSPIAEFindPage(
switch ( err )
{
-
default:
Assert( err < JET_errSuccess );
Assert( err != JET_errNoCurrentRecord );
@@ -6931,7 +6955,7 @@ ERR ErrSPIAEGetExtentAndPage(
}
else
{
- Call( ErrSPIGetFsSe( pfucb, pfucbAE, cpgRequest, cpgRequest, fSPFlags ) );
+ Call( ErrSPIGetFsSe( pfucb, pfucbAE, cpgRequest, cpgRequest ) );
}
Assert( Pcsr( pfucbAE )->FLatched() );
@@ -6953,14 +6977,16 @@ ERR ErrSPIAEGetContinuousPage(
__inout FUCB * const pfucb, // needed for ErrSPIAEGetExtentAndPage()
__inout FUCB * const pfucbAE,
_In_ const PGNO pgnoLast,
- _In_ const CPG cpgReserve,
- _In_ const BOOL fHardReserve, // ensure reserve, even if next contiguous page is available.
+ _In_ const CPG cpgAddlReserve,
+ _In_ const BOOL fSPAllocFlags,
_Out_ CSPExtentInfo * pspaeiAlloc
)
{
- ERR err = JET_errSuccess;
- FCB * const pfcb = pfucbAE->u.pfcb;
- CPG cpgEscalatingRequest = 0;
+ ERR err = JET_errSuccess;
+ FCB * const pfcb = pfucbAE->u.pfcb;
+ const CPG cpgFullReserveRequest = cpgAddlReserve ? ( cpgAddlReserve + 1 ) : 0;
+ CPG cpgEscalatingRequest = 0;
+ const BOOL fUseReserve = ( fSPAllocFlags & fSPUseActiveReserve ) != 0;
Assert( pfucb );
Assert( pfucbAE );
@@ -6976,7 +7002,6 @@ ERR ErrSPIAEGetContinuousPage(
//
if ( cpgEscalatingRequest )
{
-
// We should have had success or cpgEscalatingRequest would not be set.
CallS( err );
Assert( Pcsr( pfucbAE )->FLatched() );
@@ -6997,19 +7022,18 @@ ERR ErrSPIAEGetContinuousPage(
Assert( !Pcsr( pfucbAE )->FLatched() );
- Call( err ); // materialize the ErrBTFlagDelete() error ...
+ Call( err ); // materialize the ErrSPIWrappedBTFlagDelete() error ...
err = ErrERRCheck( errSPNoSpaceForYou );
-
}
else
{
cpgEscalatingRequest = 1;
}
- if ( fHardReserve &&
+ if ( fUseReserve &&
err >= JET_errSuccess &&
- pspaeiAlloc->CpgExtent() < cpgReserve )
+ pspaeiAlloc->CpgExtent() < cpgFullReserveRequest )
{
pspaeiAlloc->Unset();
BTUp( pfucbAE );
@@ -7017,14 +7041,17 @@ ERR ErrSPIAEGetContinuousPage(
err = ErrERRCheck( errSPNoSpaceForYou );
}
- if ( errSPNoSpaceForYou == err )
+ if ( errSPNoSpaceForYou != err )
+ {
+ Call( err );
+ }
+ else
{
-
if ( cpgEscalatingRequest == 1 )
{
- if ( cpgReserve )
+ if ( cpgAddlReserve )
{
- cpgEscalatingRequest += cpgReserve;
+ cpgEscalatingRequest += cpgAddlReserve;
}
else
{
@@ -7032,13 +7059,12 @@ ERR ErrSPIAEGetContinuousPage(
}
}
- if ( fHardReserve &&
- cpgReserve != 0 &&
- cpgReserve != cpgEscalatingRequest )
+ if ( fUseReserve &&
+ cpgAddlReserve != 0 &&
+ cpgEscalatingRequest != cpgFullReserveRequest )
{
- const CPG cpgFullReserveRequest = ( cpgReserve + 1 );
// Made this strict, but we could entertain that the request is only 10% wastage or something.
- if ( ( cpgEscalatingRequest % cpgFullReserveRequest ) != 0 )
+ if ( ( fSPExactExtent & fSPAllocFlags ) || ( ( cpgEscalatingRequest % cpgFullReserveRequest ) != 0 ) )
{
cpgEscalatingRequest = cpgFullReserveRequest;
}
@@ -7050,20 +7076,20 @@ ERR ErrSPIAEGetContinuousPage(
// Note: we don't want ErrSPIGetSe() to resize our request, we've already decided
// on a good size, so don't pass fSPOriginatingRequest.
+ const BOOL fHierarchicalSpaceAllocFlags = BoolParam( JET_paramFlight_HierarchicalSpaceAllocFlagsEnabled );
Call( ErrSPIAEGetExtentAndPage(
pfucb,
pfucbAE,
spp::ContinuousPool,
cpgEscalatingRequest,
- fSPSplitting,
+ fSPSplitting | ( fHierarchicalSpaceAllocFlags ? fSPAllocFlags : fSPNoFlags ),
pspaeiAlloc ) );
-
+ Assert( !fHierarchicalSpaceAllocFlags || !( fSPExactExtent & fSPAllocFlags ) || ( pspaeiAlloc->CpgExtent() == cpgFullReserveRequest ) );
}
// We should have succeeded or have latched some space
//
CallS( err );
- Call( err );
Assert( Pcsr( pfucbAE )->FLatched() );
Assert( pspaeiAlloc->SppPool() == spp::ContinuousPool );
@@ -7149,7 +7175,7 @@ ERR ErrSPIAEGetPage(
_In_ PGNO pgnoLast,
__inout PGNO * ppgnoAlloc,
_In_ const BOOL fSPAllocFlags,
- _In_ const CPG cpgReserve
+ _In_ const CPG cpgAddlReserve
)
{
ERR err = JET_errSuccess;
@@ -7174,7 +7200,7 @@ ERR ErrSPIAEGetPage(
if ( fSPContinuous & fSPAllocFlags )
{
- Call( ErrSPIAEGetContinuousPage( pfucb, pfucbAE, pgnoLast, cpgReserve, fSPAllocFlags & fSPUseActiveReserve, &cspaeiAlloc ) );
+ Call( ErrSPIAEGetContinuousPage( pfucb, pfucbAE, pgnoLast, cpgAddlReserve, fSPAllocFlags, &cspaeiAlloc ) );
}
else
{
@@ -7221,7 +7247,7 @@ ERR ErrSPIAEGetPage(
cspaeiAlloc.CpgExtent(),
cspaeiAlloc.SppPool() );
- Call( spAdjustedAvail.ErrConsumeSpace( cspaeiAlloc.PgnoFirst() ) );
+ Call( spAdjustedAvail.ErrConsumeSpace( cspaeiAlloc.PgnoFirst(), 1, ( fSPAllocFlags & fSPUseActiveReserve ) != 0 ) );
if ( spAdjustedAvail.FDelete() )
{
@@ -7321,9 +7347,11 @@ ERR ErrSPGetPage(
// check for valid input
//
Assert( ppgnoAlloc != NULL );
- Assert( 0 == ( fSPAllocFlags & ~fMaskSPGetPage ) );
+ Assert( 0 == ( fSPAllocFlags & ~fMaskSPGetPage ) ); // only valid options.
+ Assert( 0 == ( fSPAllocFlags & fSPUseActiveReserve ) || 0 != ( fSPAllocFlags & fSPContinuous ) || cpgDIRReserveConsumed == CpgDIRActiveSpaceRequestReserve( pfucb ) ); // fSPUseActiveReserve requires fSPContinuous to actually reserve space.
+
- CPG cpgAddlReserve = 0;
+ CPG cpgAddlReserve = 0;
if ( fSPAllocFlags & fSPNewExtent )
{
cpgAddlReserve = 15;
@@ -7466,7 +7494,7 @@ LOCAL ERR ErrSPIFreeSEToParent(
// get parentFDP's root pgno
// cursor passed in should be at root of tree
// so we can access pgnoParentFDP from the external header
- const PGNO pgnoParentFDP = PgnoSPIParentFDP( pfucb );
+ const PGNO pgnoParentFDP = PgnoSPParentFDP( pfucb );
if ( pgnoParentFDP == pgnoNull )
{
// This is the root DB and its parent is the file system, so there's nothing to release
@@ -8006,7 +8034,7 @@ ERR ErrSPIAERemoveInsertionRegion(
return err;
}
-LOCAL VOID SPIReportSpaceLeak( _In_ const FUCB* const pfucb, _In_ const ERR err, _In_ const PGNO pgnoFirst, _In_ const CPG cpg, __in_z const CHAR* const szTag )
+VOID SPReportSpaceLeak( _In_ const FUCB* const pfucb, _In_ const ERR err, _In_ const PGNO pgnoFirst, _In_ const CPG cpg, __in_z const CHAR* const szTag )
{
Assert( pfucb != NULL );
Expected( err < JET_errSuccess );
@@ -8525,6 +8553,7 @@ ERR ErrSPCaptureNonRevertableFDPRootPage( PIB *ppib, FCB* pfcbFDPToFree, const P
PgnoRoot( pfucb ),
dbtimeNil,
fRBSDeletedTableRootPage,
+ fFalse,
pfucb->ppib->BfpriPriority( pfucb->ifmp ),
*tcScope ) );
cpgCaptured++;
@@ -8545,6 +8574,7 @@ ERR ErrSPCaptureNonRevertableFDPRootPage( PIB *ppib, FCB* pfcbFDPToFree, const P
pfcbT->PgnoFDP(),
dbtimeNil,
fRBSDeletedTableRootPage,
+ fFalse,
pfucb->ppib->BfpriPriority( pfucb->ifmp ),
*tcScope ) );
cpgCaptured++;
@@ -8563,6 +8593,7 @@ ERR ErrSPCaptureNonRevertableFDPRootPage( PIB *ppib, FCB* pfcbFDPToFree, const P
pgnoLVRoot,
dbtimeNil,
fRBSDeletedTableRootPage,
+ fFalse,
pfucb->ppib->BfpriPriority( pfucb->ifmp ),
*tcScope ) );
cpgCaptured++;
@@ -8583,7 +8614,7 @@ ERR ErrSPCaptureNonRevertableFDPRootPage( PIB *ppib, FCB* pfcbFDPToFree, const P
HandleError:
if ( err < JET_errSuccess )
{
- SPIReportSpaceLeak( pfucb, err, pfcbFDPToFree->PgnoFDP(), 1, "CaptureNonRevertableFDPRootPage" );
+ SPReportSpaceLeak( pfucb, err, pfcbFDPToFree->PgnoFDP(), 1, "CaptureNonRevertableFDPRootPage" );
}
if ( pfucbNil != pfucb )
@@ -8681,7 +8712,7 @@ ERR ErrSPCaptureSpaceTreePages( FUCB* const pfucbParent, FCB* pfcb, CPG* pcpgSna
HandleError:
if ( err < JET_errSuccess )
{
- SPIReportSpaceLeak( pfucbOE, err, pgnoFirst, cpgExtent, "CaptureSpaceTreePages" );
+ SPReportSpaceLeak( pfucbOE, err, pgnoFirst, cpgExtent, "CaptureSpaceTreePages" );
}
if ( pfucbOE != pfucbNil )
@@ -8940,7 +8971,7 @@ ERR ErrSPFreeExt( FUCB* const pfucb, const PGNO pgnoFirst, const CPG cpgSize, co
err,
err ) );
- SPIReportSpaceLeak( pfucb, err, pgnoFirst, cpgSize, szTag );
+ SPReportSpaceLeak( pfucb, err, pgnoFirst, cpgSize, szTag );
}
else
{
@@ -9624,7 +9655,7 @@ LOCAL ERR ErrSPILRProcessObjectSpaceOwnershipSetPgnos(
{
Call( ErrErrArrayPgnoToJetErr( parrShelved->ErrSetCapacity( 2 * ( parrShelved->Size() + 1 ) ) ) );
}
- Call( ErrErrArrayPgnoToJetErr( parrShelved->ErrSetEntry( parrShelved->Size(), (CPgnoFlagged)pgno ) ) );
+ Call( ErrErrArrayPgnoToJetErr( parrShelved->ErrAppendEntry( (CPgnoFlagged)pgno ) ) );
}
else
{
@@ -10931,7 +10962,7 @@ ERR ErrSPFreeFDP(
// get parent FDP pgno
//
- Assert( pgnoFDPParent == PgnoSPIParentFDP( pfucb ) );
+ Assert( pgnoFDPParent == PgnoSPParentFDP( pfucb ) );
Assert( pgnoFDPParent == PgnoFDP( pfucbParent ) );
if ( !pfucb->u.pfcb->FSpaceInitialized() )
@@ -11433,9 +11464,7 @@ LOCAL ERR ErrSPIAddSecondaryExtent(
const EXTENTINFO& extinfoReleased = parreiReleased->Entry( parreiReleased->Size() - 1 );
Assert( extinfoReleased.FValid() && ( extinfoReleased.CpgExtent() > 0 ) );
Call( ErrSPIAEFreeExt( pfucb, extinfoReleased.PgnoFirst(), extinfoReleased.CpgExtent() ) );
- CallS( ( parreiReleased->ErrSetSize( parreiReleased->Size() - 1 ) == CArray::ERR::errSuccess ) ?
- JET_errSuccess :
- ErrERRCheck( JET_errOutOfMemory ) );
+ (void)parreiReleased->FRemoveLastEntry();
}
Assert( !Pcsr( pfucbAE )->FLatched() );
@@ -11468,7 +11497,7 @@ LOCAL ERR ErrSPIAddSecondaryExtent(
Assert( ( err < JET_errSuccess ) || ( fAddedToOwnExt && fAddedToAvailExt ) );
if ( fAddedToOwnExt && !fAddedToAvailExt )
{
- SPIReportSpaceLeak( pfucb, err, pgnoLast - cpgAvailable + 1, cpgAvailable, "NewExt" );
+ SPReportSpaceLeak( pfucb, err, pgnoLast - cpgAvailable + 1, cpgAvailable, "NewExt" );
}
return err;
@@ -11860,7 +11889,7 @@ LOCAL ERR ErrSPIExtendDB(
// If Shrink is running, signal it to bail and let the database grow IFF
// if we can violate the max DB size constraint, which is a proxy for when
// not doing so would lead to space leaks.
- if ( g_rgfmp[pfucbRoot->ifmp].FShrinkIsActive() )
+ if ( g_rgfmp[pfucbRoot->ifmp].FShrinkIsRunning() )
{
if ( fMayViolateMaxSize )
{
@@ -11923,7 +11952,7 @@ LOCAL ERR ErrSPIExtendDB(
EXTENTINFO extinfoReleased;
extinfoReleased.pgnoLastInExtent = pgnoSELastAdj + cpgAvail;
extinfoReleased.cpgExtent = cpgAvail;
- Call( ( parreiReleased->ErrSetEntry( parreiReleased->Size(), extinfoReleased ) == CArray::ERR::errSuccess ) ?
+ Call( ( parreiReleased->ErrAppendEntry( extinfoReleased ) == CArray::ERR::errSuccess ) ?
JET_errSuccess :
ErrERRCheck( JET_errOutOfMemory ) );
}
@@ -12095,7 +12124,6 @@ ERR ErrSPExtendDB(
pfucbAE,
cpgSEMin,
cpgSEMin,
- 0,
fTrue,
fPermitAsyncExtension ) );
@@ -13238,9 +13266,9 @@ LOCAL ERR ErrSPIReserveSPBufPagesForSpaceTree(
// Make sure we have enough room in the array.
if ( parreiReleased != NULL )
{
- Call( ( parreiReleased->ErrSetEntry( parreiReleased->Size(), extinfoReleased ) == CArray::ERR::errSuccess ) ?
- JET_errSuccess :
- ErrERRCheck( JET_errOutOfMemory ) );
+ Call( ( parreiReleased->ErrAppendEntry( extinfoReleased ) == CArray::ERR::errSuccess ) ?
+ JET_errSuccess :
+ ErrERRCheck( JET_errOutOfMemory ) );
}
else
{
@@ -13480,9 +13508,7 @@ LOCAL ERR ErrSPIReserveSPBufPages(
const EXTENTINFO& extinfoReleased = arreiReleased[ arreiReleased.Size() - 1 ];
Assert( extinfoReleased.FValid() && ( extinfoReleased.CpgExtent() > 0 ) );
Call( ErrSPIAEFreeExt( pfucb, extinfoReleased.PgnoFirst(), extinfoReleased.CpgExtent(), pfucbParentLocal ) );
- CallS( ( arreiReleased.ErrSetSize( arreiReleased.Size() - 1 ) == CArray::ERR::errSuccess ) ?
- JET_errSuccess :
- ErrERRCheck( JET_errOutOfMemory ) );
+ (void)arreiReleased.FRemoveLastEntry();
fNeedRefill = fTrue;
}
}
@@ -13519,7 +13545,7 @@ LOCAL ERR ErrSPIReserveSPBufPages(
if ( !fExtentFreed )
{
- SPIReportSpaceLeak( pfucb, err, extinfo.PgnoFirst(), (CPG)extinfo.CpgExtent(), "SpBuffer" );
+ SPReportSpaceLeak( pfucb, err, extinfo.PgnoFirst(), (CPG)extinfo.CpgExtent(), "SpBuffer" );
}
}
@@ -14005,7 +14031,6 @@ LOCAL ERR ErrSPIGetFsSe(
FUCB * const pfucbAE,
const CPG cpgReq,
const CPG cpgMin,
- const ULONG fSPFlags,
const BOOL fExact,
const BOOL fPermitAsyncExtension,
const BOOL fMayViolateMaxSize )
@@ -14364,6 +14389,8 @@ LOCAL ERR ErrSPITrimRegion(
{
ERR err;
+ Expected( !g_rgfmp[ ifmp ].FShrinkIsActive() );
+
*pcpgSparseBeforeThisExtent = 0;
*pcpgSparseAfterThisExtent = 0;
@@ -14520,15 +14547,15 @@ LOCAL ERR ErrSPIAddFreedExtent(
Assert( Pcsr( pfucbAE )->FLatched() );
if ( ( pgnoParentFDP == pgnoSystemRoot ) &&
+ !g_rgfmp[ ifmp ].FShrinkIsActive() &&
g_rgfmp[ ifmp ].FTrimSupported() &&
- ( ( GrbitParam( g_rgfmp[ ifmp ].Pinst(), JET_paramEnableShrinkDatabase ) & ( JET_bitShrinkDatabaseOn | JET_bitShrinkDatabaseRealtime ) ) ==
- ( JET_bitShrinkDatabaseOn | JET_bitShrinkDatabaseRealtime ) ) )
+ ( ( GrbitParam( g_rgfmp[ ifmp ].Pinst(), JET_paramEnableShrinkDatabase ) & ( JET_bitShrinkDatabaseOn | JET_bitShrinkDatabaseRealtime ) ) == ( JET_bitShrinkDatabaseOn | JET_bitShrinkDatabaseRealtime ) ) )
{
// In-line version of database trim. Swallow the errors because at this point in the
// code an error freeing up on-disk space should not block freeing up the extent.
CPG cpgSparseBeforeThisExtent = 0;
CPG cpgSparseAfterThisExtent = 0;
- (void) ErrSPITrimRegion( ifmp, pfucbAE->ppib, pgnoLast, cpgSize, &cpgSparseBeforeThisExtent, &cpgSparseAfterThisExtent );
+ (void)ErrSPITrimRegion( ifmp, pfucbAE->ppib, pgnoLast, cpgSize, &cpgSparseBeforeThisExtent, &cpgSparseAfterThisExtent );
}
HandleError:
@@ -14724,8 +14751,9 @@ LOCAL ERR ErrSPIExtGetExtentListInfo(
}
-LOCAL ERR ErrSPIGetInfo(
+ERR ErrSPIGetInfo(
FUCB *pfucb,
+ const PGNO pgnoHighest,
CPG *pcpgTotal,
CPG *pcpgReserved,
CPG *pcpgShelved,
@@ -14786,94 +14814,99 @@ LOCAL ERR ErrSPIGetInfo(
{
const CSPExtentInfo cspext( pfucb );
- if( pcprintf )
+ if ( ( pgnoHighest == pgnoNull ) || ( !cspext.FEmptyExtent() && ( pgnoHighest >= cspext.PgnoFirst() ) ) )
{
- CPG cpgSparse = 0;
+ Expected( ( pgnoHighest == pgnoNull ) || ( pgnoHighest >= cspext.PgnoLast() ) );
- if ( !cspext.FEmptyExtent() )
+ if ( pcprintf )
{
- (void) ErrSPIGetSparseInfoRange( &g_rgfmp[ pfucb->ifmp ], cspext.PgnoFirst(), cspext.PgnoLast(), &cpgSparse );
- }
+ CPG cpgSparse = 0;
- if( pgnoLastSeen != Pcsr( pfucb )->Pgno() )
- {
- pgnoLastSeen = Pcsr( pfucb )->Pgno();
+ if ( !cspext.FEmptyExtent() )
+ {
+ (void) ErrSPIGetSparseInfoRange( &g_rgfmp[ pfucb->ifmp ], cspext.PgnoFirst(), cspext.PgnoLast(), &cpgSparse );
+ }
- ++cpgSeen;
- }
+ if( pgnoLastSeen != Pcsr( pfucb )->Pgno() )
+ {
+ pgnoLastSeen = Pcsr( pfucb )->Pgno();
- (*pcprintf)( "%30s: %s[%5d]:\t%6d-%6d (%3d) %s%s",
- SzNameOfTable( pfucb ),
- SzSpaceTreeType( pfucb ),
- Pcsr( pfucb )->Pgno(),
- cspext.FEmptyExtent() ? 0 : cspext.PgnoFirst(),
- cspext.FEmptyExtent() ? cspext.PgnoMarker() : cspext.PgnoLast(),
- cspext.CpgExtent(),
- FNDDeleted( pfucb->kdfCurr ) ? " (DEL)" : "",
- ( cspext.ErrCheckCorrupted( ) < JET_errSuccess ) ? " (COR)" : ""
- );
- if ( cspext.FNewAvailFormat() )
- {
- (*pcprintf)( " Pool: %d %s",
- cspext.SppPool(),
- cspext.FNewAvailFormat() ? "(fNewAvailFormat)" : ""
+ ++cpgSeen;
+ }
+
+ (*pcprintf)( "%30s: %s[%5d]:\t%6d-%6d (%3d) %s%s",
+ SzNameOfTable( pfucb ),
+ SzSpaceTreeType( pfucb ),
+ Pcsr( pfucb )->Pgno(),
+ cspext.FEmptyExtent() ? 0 : cspext.PgnoFirst(),
+ cspext.FEmptyExtent() ? cspext.PgnoMarker() : cspext.PgnoLast(),
+ cspext.CpgExtent(),
+ FNDDeleted( pfucb->kdfCurr ) ? " (DEL)" : "",
+ ( cspext.ErrCheckCorrupted( ) < JET_errSuccess ) ? " (COR)" : ""
);
+ if ( cspext.FNewAvailFormat() )
+ {
+ (*pcprintf)( " Pool: %d %s",
+ cspext.SppPool(),
+ cspext.FNewAvailFormat() ? "(fNewAvailFormat)" : ""
+ );
+ }
+ if ( cpgSparse > 0 )
+ {
+ (*pcprintf)( " cpgSparse: %3d", cpgSparse );
+ }
+ (*pcprintf)( "\n" );
+
+ ++cRecords;
+ if( FNDDeleted( pfucb->kdfCurr ) )
+ {
+ ++cRecordsDeleted;
+ }
}
- if ( cpgSparse > 0 )
+
+ if ( cspext.SppPool() != spp::ShelvedPool )
{
- (*pcprintf)( " cpgSparse: %3d", cpgSparse );
+ *pcpgTotal += cspext.CpgExtent();
}
- (*pcprintf)( "\n" );
- ++cRecords;
- if( FNDDeleted( pfucb->kdfCurr ) )
+ if ( pcpgReserved && cspext.FNewAvailFormat() &&
+ ( cspext.SppPool() == spp::ContinuousPool ) )
{
- ++cRecordsDeleted;
+ *pcpgReserved += cspext.CpgExtent();
}
- }
-
- if ( cspext.SppPool() != spp::ShelvedPool )
- {
- *pcpgTotal += cspext.CpgExtent();
- }
-
- if ( pcpgReserved && cspext.FNewAvailFormat() &&
- ( cspext.SppPool() == spp::ContinuousPool ) )
- {
- *pcpgReserved += cspext.CpgExtent();
- }
- BOOL fSuppressExtent = fFalse;
+ BOOL fSuppressExtent = fFalse;
- if ( pcpgShelved && cspext.FNewAvailFormat() &&
- ( cspext.SppPool() == spp::ShelvedPool ) )
- {
- if ( cspext.PgnoLast() > g_rgfmp[ pfucb->ifmp ].PgnoLast() )
+ if ( pcpgShelved && cspext.FNewAvailFormat() &&
+ ( cspext.SppPool() == spp::ShelvedPool ) )
{
- Assert( cspext.PgnoFirst() > g_rgfmp[ pfucb->ifmp ].PgnoLast() );
- *pcpgShelved += cspext.CpgExtent();
- }
- else
- {
- fSuppressExtent = fTrue;
+ if ( cspext.PgnoLast() > g_rgfmp[ pfucb->ifmp ].PgnoLast() )
+ {
+ Assert( cspext.PgnoFirst() > g_rgfmp[ pfucb->ifmp ].PgnoLast() );
+ *pcpgShelved += cspext.CpgExtent();
+ }
+ else
+ {
+ fSuppressExtent = fTrue;
+ }
}
- }
-
- if ( fExtentList && !fSuppressExtent )
- {
- Assert( iext < cext );
- // be sure to leave space for the sentinels
- // (if no more room, we still want to keep
- // calculating page count - we just can't
- // keep track of individual extents anymore
- //
- Assert( iext + *pcextSentinelsRemaining <= cext );
- if ( iext + *pcextSentinelsRemaining < cext )
+ if ( fExtentList && !fSuppressExtent )
{
- rgext[iext].pgnoLastInExtent = cspext.PgnoLast();
- rgext[iext].cpgExtent = cspext.CpgExtent();
- iext++;
+ Assert( iext < cext );
+
+ // be sure to leave space for the sentinels
+ // (if no more room, we still want to keep
+ // calculating page count - we just can't
+ // keep track of individual extents anymore
+ //
+ Assert( iext + *pcextSentinelsRemaining <= cext );
+ if ( iext + *pcextSentinelsRemaining < cext )
+ {
+ rgext[iext].pgnoLastInExtent = cspext.PgnoLast();
+ rgext[iext].cpgExtent = cspext.CpgExtent();
+ iext++;
+ }
}
}
@@ -14881,7 +14914,9 @@ LOCAL ERR ErrSPIGetInfo(
if ( err < 0 )
{
if ( err != JET_errNoCurrentRecord )
+ {
goto HandleError;
+ }
break;
}
}
@@ -15669,6 +15704,7 @@ ERR ErrSPGetInfo(
Call( ErrSPIGetInfo(
pfucbSpace,
+ pgnoNull,
pcpgOwnExtTotal,
NULL,
NULL,
@@ -15826,6 +15862,7 @@ ERR ErrSPGetInfo(
Call( ErrSPIGetInfo(
pfucbSpace,
+ pgnoNull,
pcpgAvailExtTotal,
pcpgReservedExtTotal,
pcpgShelvedExtTotal,
@@ -16064,6 +16101,7 @@ ERR ErrSPIGetCpgOwnedAndAvail(
Call( ErrSPIGetInfo(
pfucbOE,
+ pgnoNull,
pcpgOwnExtTotal,
NULL,
NULL,
@@ -16075,6 +16113,7 @@ ERR ErrSPIGetCpgOwnedAndAvail(
Call( ErrSPIGetInfo(
pfucbAE,
+ pgnoNull,
pcpgAvailExtTotal,
NULL,
NULL,
diff --git a/dev/ese/src/ese/sysinit.cxx b/dev/ese/src/ese/sysinit.cxx
index cb09e285..94272cd9 100644
--- a/dev/ese/src/ese/sysinit.cxx
+++ b/dev/ese/src/ese/sysinit.cxx
@@ -11,6 +11,16 @@
BOOL g_fDBGPerfOutput = fFalse;
#endif /* DEBUG || PERFDUMP */
+// This is here, because jettest.cxx is only compiled in eselibwithtest.dll
+
+#ifndef ENABLE_JET_UNIT_TEST
+
+BOOL FInEmbeddedUnitTest()
+{
+ return fFalse;
+}
+
+#endif // ENABLE_JET_UNIT_TEST
#ifdef DEBUG
@@ -561,8 +571,8 @@ ERR INST::ErrINSTTerm( TERMTYPE termtype )
else
{
// allow for improper usage in test (e.g.: terminating the instance
- // with an outstanding transaction).
- if ( !FNegTest( fInvalidUsage ) )
+ // with an outstanding transaction) or instance unavailable.
+ if ( !FNegTest( fInvalidUsage ) && !FInstanceUnavailable() )
{
FCBAssertAllClean( this );
}
diff --git a/dev/ese/src/ese/sysparamtable.g.cxx b/dev/ese/src/ese/sysparamtable.g.cxx
index 7a1eed6d..49ae6f6e 100644
--- a/dev/ese/src/ese/sysparamtable.g.cxx
+++ b/dev/ese/src/ese/sysparamtable.g.cxx
@@ -63,7 +63,7 @@ JetParam g_rgparamRaw[] =
NORMAL_PARAM(JET_paramDeleteOutOfRangeLogs, CJetParam::typeBoolean, 0, 0, 0, 1, 0, -1, 0),
NORMAL_PARAM(JET_paramAccessDeniedRetryPeriod, CJetParam::typeInteger, 0, 1, 0, 0, 0, -1, 10000),
NORMAL_PARAM(JET_paramEnableIndexCleanup, CJetParam::typeBoolean, 0, 0, 0, 0, 0, -1, 1),
- NORMAL_PARAM(JET_paramFlight_SmoothIoTestPermillage, CJetParam::typeInteger, 1, 0, 0, 1, 0, 1000, 0),
+ NORMAL_PARAM(JET_paramFlight_HierarchicalSpaceAllocFlagsEnabled, CJetParam::typeBoolean, 1, 1, 0, 1, 0, -1, fTrue),
NORMAL_PARAM(JET_paramElasticWaypointLatency, CJetParam::typeInteger, 1, 0, 0, 0, 0, 10, JET_paramElasticWaypointLatency_DEFAULT),
NORMAL_PARAM(JET_paramFlight_SynchronousLVCleanup, CJetParam::typeBoolean, 1, 0, 0, 0, 0, -1, 0),
NORMAL_PARAM(JET_paramFlight_RBSRevertIOUrgentLevel, CJetParam::typeInteger, 1, 0, 0, 0, 0, 127, 8),
@@ -102,7 +102,7 @@ JetParam g_rgparamRaw[] =
NORMAL_PARAM(JET_paramFlight_LowMetedOpsThreshold, CJetParam::typeInteger, 0, 0, 0, 1, 0, 1024, 40),
NORMAL_PARAM(JET_paramFlight_MetedOpStarvedThreshold, CJetParam::typeInteger, 0, 0, 0, 1, 50, 2147483647, 3000),
NORMAL_PARAM(JET_paramFlight_MaxRBSBuffers, CJetParam::typeInteger, 0, 0, 0, 0, 1, 2147483647, 20),
- NORMAL_PARAM(JET_paramFlight_EnableShrinkArchiving, CJetParam::typeBoolean, 1, 0, 0, 0, 0, 1, 1),
+ NORMAL_PARAM(JET_paramFlight_EnableShrinkArchiving, CJetParam::typeBoolean, 1, 0, 0, 0, 0, 1, 0),
NORMAL_PARAM(JET_paramFlight_EnableBackupDuringRecovery, CJetParam::typeBoolean, 1, 0, 0, 0, 0, -1, 0),
NORMAL_PARAM(JET_paramFlight_RBSRollIntervalSec, CJetParam::typeInteger, 1, 0, 0, 0, 0, 604800, 43200),
NORMAL_PARAM(JET_paramFlight_RBSMaxRequiredRange, CJetParam::typeInteger, 1, 0, 0, 0, 0, 10000, 1000),
@@ -129,8 +129,8 @@ JetParam g_rgparamRaw[] =
NORMAL_PARAM(JET_paramAlternateDatabaseRecoveryPath, CJetParam::typeFolder, 0, 0, 0, 1, 0, 246, L""),
NORMAL_PARAM(JET_paramFlight_ExtentPageCountCacheVerifyOnly, CJetParam::typeBoolean, 1, 1, 0, 0, 0, -1, 0),
NORMAL_PARAM(JET_paramFlight_EnablePgnoFDPLastSetTime, CJetParam::typeBoolean, 1, 0, 0, 1, 0, -1, fTrue),
- NORMAL_PARAM(JET_paramFlight_EnableScanCheck2Flags, CJetParam::typeBoolean, 1, 0, 0, 1, 0, -1, fTrue),
- NORMAL_PARAM(JET_paramFlight_EnableExtentFreed2, CJetParam::typeBoolean, 1, 0, 0, 1, 0, -1, fTrue),
+ NORMAL_PARAM(JET_paramFlight_EnableFDPDeleteFlagCheckOnExtentFreedRedo, CJetParam::typeBoolean, 1, 0, 0, 1, 0, -1, fTrue),
+ NORMAL_PARAM(JET_paramFlight_RBSRaiseCorruptionOnRBSFDPToBeDeleted, CJetParam::typeBoolean, 1, 0, 0, 1, 0, -1, fTrue),
NORMAL_PARAM(JET_paramFlight_RBSLargeRevertableDeletePages, CJetParam::typeInteger, 1, 0, 0, 0, 0, 2147483647, 0),
NORMAL_PARAM(JET_paramFlight_RBSRevertableDeleteIfTooSoonTimeNull, CJetParam::typeBoolean, 1, 0, 0, 0, 0, -1, fFalse),
IGNORED_PARAM(JET_paramDBAPageAvailMin, CJetParam::typeInteger, 1, 1, 0, 0, 0, -1, 1280),
@@ -198,7 +198,7 @@ JetParam g_rgparamRaw[] =
NORMAL_PARAM(JET_paramHungIOActions, CJetParam::typeInteger, 1, 1, 1, 1, JET_bitNil, (JET_bitHungIOEvent|JET_bitHungIOCancel|JET_bitHungIODebug|JET_bitHungIOEnforce|JET_bitHungIOTimeout), JET_bitHungIOEvent),
NORMAL_PARAM(JET_paramMinDataForXpress, CJetParam::typeInteger, 1, 1, 1, 1, 0, 2147483647, 1024),
CUSTOM_PARAM3(JET_paramEnableShrinkDatabase, CJetParam::typeGrbit, 0, 0, 0, 1, 0, 0xffff, JET_paramEnableShrinkDatabase_DEFAULT, JET_paramEnableShrinkDatabase_DEFAULT, CJetParam::GetInteger, SetShrinkDatabaseParam, CJetParam::CloneDefault),
- ILLEGAL_PARAM(185),
+ CUSTOM_PARAM3(JET_paramFlight_CacheTraceSamplingRatio, CJetParam::typeInteger, 0, 1, 0, 0, 0, 2147483647, 1, 1, CJetParam::GetInteger, SetCacheTraceSamplingRatio, CJetParam::CloneDefault),
NORMAL_PARAM(JET_paramProcessFriendlyName, CJetParam::typeString, 0, 1, 1, 1, 0, JET_cbNameMost, L""),
NORMAL_PARAM(JET_paramDurableCommitCallback, CJetParam::typePointer, 1, 0, 0, 1, 0, -1, NULL),
IGNORED_PARAM(JET_paramEnableSqm, CJetParam::typeInteger, 0, 0, 0, 1, JET_sqmDisable, JET_sqmFromCEIP, JET_sqmEnable),
@@ -240,6 +240,8 @@ JetParam g_rgparamRaw[] =
NORMAL_PARAM(JET_paramEnableBlockCache, CJetParam::typeBoolean, 1, 1, 1, 0, 0, 1, 0),
NORMAL_PARAM(JET_paramDeferredIndexPopulateRowsPerTransaction, CJetParam::typeInteger, 1, 0, 0, 0, 1, 2147483647, 1000),
NORMAL_PARAM(JET_paramEnableBlockCacheDetach, CJetParam::typeBoolean, 1, 1, 1, 0, 0, 1, 0),
+ NORMAL_PARAM(JET_paramFlight_UseCngAes256Implementation, CJetParam::typeBoolean, 0, 1, 0, 0, 0, 1, JET_paramFlight_UseCngAes256ImplementationDEFAULT),
+ NORMAL_PARAM(JET_paramFlight_ContiguousExtentMoveShrinkEnabled, CJetParam::typeBoolean, 1, 1, 0, 1, 0, -1, JET_paramFlight_ContiguousExtentMoveShrinkEnabledDEFAULT),
ILLEGAL_PARAM(JET_paramMaxValueInvalid),
};
@@ -301,7 +303,7 @@ static_assert( JET_paramEventLoggingLevel == 51, "The order of defintion for JET
static_assert( JET_paramDeleteOutOfRangeLogs == 52, "The order of defintion for JET_paramDeleteOutOfRangeLogs in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramAccessDeniedRetryPeriod == 53, "The order of defintion for JET_paramAccessDeniedRetryPeriod in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramEnableIndexCleanup == 54, "The order of defintion for JET_paramEnableIndexCleanup in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
-static_assert( JET_paramFlight_SmoothIoTestPermillage == 55, "The order of defintion for JET_paramFlight_SmoothIoTestPermillage in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
+static_assert( JET_paramFlight_HierarchicalSpaceAllocFlagsEnabled == 55, "The order of defintion for JET_paramFlight_HierarchicalSpaceAllocFlagsEnabled in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramElasticWaypointLatency == 56, "The order of defintion for JET_paramElasticWaypointLatency in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramFlight_SynchronousLVCleanup == 57, "The order of defintion for JET_paramFlight_SynchronousLVCleanup in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramFlight_RBSRevertIOUrgentLevel == 58, "The order of defintion for JET_paramFlight_RBSRevertIOUrgentLevel in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
@@ -362,8 +364,8 @@ static_assert( JET_paramIndexTuplesToIndexMax == 112, "The order of defintion fo
static_assert( JET_paramAlternateDatabaseRecoveryPath == 113, "The order of defintion for JET_paramAlternateDatabaseRecoveryPath in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramFlight_ExtentPageCountCacheVerifyOnly == 114, "The order of defintion for JET_paramFlight_ExtentPageCountCacheVerifyOnly in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramFlight_EnablePgnoFDPLastSetTime == 115, "The order of defintion for JET_paramFlight_EnablePgnoFDPLastSetTime in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
-static_assert( JET_paramFlight_EnableScanCheck2Flags == 116, "The order of defintion for JET_paramFlight_EnableScanCheck2Flags in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
-static_assert( JET_paramFlight_EnableExtentFreed2 == 117, "The order of defintion for JET_paramFlight_EnableExtentFreed2 in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
+static_assert( JET_paramFlight_EnableFDPDeleteFlagCheckOnExtentFreedRedo == 116, "The order of defintion for JET_paramFlight_EnableFDPDeleteFlagCheckOnExtentFreedRedo in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
+static_assert( JET_paramFlight_RBSRaiseCorruptionOnRBSFDPToBeDeleted == 117, "The order of defintion for JET_paramFlight_RBSRaiseCorruptionOnRBSFDPToBeDeleted in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramFlight_RBSLargeRevertableDeletePages == 118, "The order of defintion for JET_paramFlight_RBSLargeRevertableDeletePages in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramFlight_RBSRevertableDeleteIfTooSoonTimeNull == 119, "The order of defintion for JET_paramFlight_RBSRevertableDeleteIfTooSoonTimeNull in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramDBAPageAvailMin == 120, "The order of defintion for JET_paramDBAPageAvailMin in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
@@ -431,7 +433,7 @@ static_assert( JET_paramHungIOThreshold == 181, "The order of defintion for JET_
static_assert( JET_paramHungIOActions == 182, "The order of defintion for JET_paramHungIOActions in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramMinDataForXpress == 183, "The order of defintion for JET_paramMinDataForXpress in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramEnableShrinkDatabase == 184, "The order of defintion for JET_paramEnableShrinkDatabase in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
-static_assert( 185 == 185, "The order of defintion for 185 in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
+static_assert( JET_paramFlight_CacheTraceSamplingRatio == 185, "The order of defintion for JET_paramFlight_CacheTraceSamplingRatio in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramProcessFriendlyName == 186, "The order of defintion for JET_paramProcessFriendlyName in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramDurableCommitCallback == 187, "The order of defintion for JET_paramDurableCommitCallback in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramEnableSqm == 188, "The order of defintion for JET_paramEnableSqm in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
@@ -467,4 +469,6 @@ static_assert( JET_paramPerfmonRefreshInterval == 217, "The order of defintion f
static_assert( JET_paramEnableBlockCache == 218, "The order of defintion for JET_paramEnableBlockCache in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramDeferredIndexPopulateRowsPerTransaction == 219, "The order of defintion for JET_paramDeferredIndexPopulateRowsPerTransaction in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
static_assert( JET_paramEnableBlockCacheDetach == 220, "The order of defintion for JET_paramEnableBlockCacheDetach in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
-static_assert( JET_paramMaxValueInvalid == 221, "The order of defintion for JET_paramMaxValueInvalid in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
+static_assert( JET_paramFlight_UseCngAes256Implementation == 221, "The order of defintion for JET_paramFlight_UseCngAes256Implementation in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
+static_assert( JET_paramFlight_ContiguousExtentMoveShrinkEnabled == 222, "The order of defintion for JET_paramFlight_ContiguousExtentMoveShrinkEnabled in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
+static_assert( JET_paramMaxValueInvalid == 223, "The order of defintion for JET_paramMaxValueInvalid in sysparam.xml must follow the numerical ordering of its value (as defined in jethdr.w)." );
diff --git a/dev/ese/src/ese/sysver.cxx b/dev/ese/src/ese/sysver.cxx
index 56eb1453..88866579 100644
--- a/dev/ese/src/ese/sysver.cxx
+++ b/dev/ese/src/ese/sysver.cxx
@@ -279,22 +279,20 @@ ERR ErrLGFindHighestMatchingLogMajors( _In_ const LogVersion& lgvFromLogHeader,
}
// create a formatted string at end of a given buffer
+// Explicitly NOT part of the OSStr API because it's very
+// inefficient in the wrong context (like a loop on a big string
-void __cdecl OSStrCbAppendFormatW ( __inout_bcount(cbBuffer) PWSTR wszBuffer, size_t cbBuffer, __format_string PCWSTR cwszFormat, ... )
+void __cdecl AppendFormatW ( __inout_bcount(cbBuffer) PWSTR wszBuffer, size_t cbBuffer, __format_string PCWSTR cwszFormat, ... )
{
va_list alist;
va_start( alist, cwszFormat );
const size_t cbUsed = LOSStrLengthW( wszBuffer ) * sizeof(WCHAR);
Assert( cbUsed < cbBuffer ); // did someone pass in an unit buffer?
Assert( ( cbUsed % sizeof(WCHAR) ) == 0 );
- HRESULT hr = StringCbVPrintfW( wszBuffer + ( cbUsed / sizeof(WCHAR) ), cbBuffer - cbUsed, cwszFormat, alist );
-#ifdef DEBUG
- CallS( ErrFromStrsafeHr( hr ) );
-#endif
+ OSStrCbVFormatW( wszBuffer + ( cbUsed / sizeof(WCHAR) ), cbBuffer - cbUsed, cwszFormat, alist );
va_end( alist );
}
-
// A nice formatting of the JET_paramEngineFormatValue setting ... the problem is we have an enum possibly combined with a
// flag and so it is hard to translate / easily lookup if we just print it either as decimal or hex (because the EFV values
// are not in hex).
@@ -343,22 +341,22 @@ void FormatEfvSetting( const JET_ENGINEFORMATVERSION efvFullParam, _Out_writes_b
BOOL fNeedOr = fFalse;
if ( efvBaseValue != 0 )
{
- OSStrCbAppendFormatW( wszEfvSetting, cbEfvSetting, L"%d", efvBaseValue );
+ AppendFormatW( wszEfvSetting, cbEfvSetting, L"%d", efvBaseValue );
fNeedOr = fTrue;
}
if ( fJET_efvUseEngineDefault )
{
- OSStrCbAppendFormatW( wszEfvSetting, cbEfvSetting, L"%hs%hs", fNeedOr ? " | " : "", "JET_efvUseEngineDefault" );
+ AppendFormatW( wszEfvSetting, cbEfvSetting, L"%hs%hs", fNeedOr ? " | " : "", "JET_efvUseEngineDefault" );
fNeedOr = fTrue;
}
if ( fJET_efvUsePersistedFormat )
{
- OSStrCbAppendFormatW( wszEfvSetting, cbEfvSetting, L"%hs%hs", fNeedOr ? " | " : "", "JET_efvUsePersistedFormat" );
+ AppendFormatW( wszEfvSetting, cbEfvSetting, L"%hs%hs", fNeedOr ? " | " : "", "JET_efvUsePersistedFormat" );
fNeedOr = fTrue;
}
if ( fJET_efvAllowHigherPersistedFormat )
{
- OSStrCbAppendFormatW( wszEfvSetting, cbEfvSetting, L"%hs%hs", fNeedOr ? " | " : "", "JET_efvAllowHigherPersistedFormat" );
+ AppendFormatW( wszEfvSetting, cbEfvSetting, L"%hs%hs", fNeedOr ? " | " : "", "JET_efvAllowHigherPersistedFormat" );
fNeedOr = fTrue;
}
OSStrCbAppendW( wszEfvSetting, cbEfvSetting, L")" );
diff --git a/dev/ese/src/ese/ver.cxx b/dev/ese/src/ese/ver.cxx
index ad3a1897..64a2ac01 100644
--- a/dev/ese/src/ese/ver.cxx
+++ b/dev/ese/src/ese/ver.cxx
@@ -7,7 +7,6 @@
#include "PageSizeClean.hxx"
-
///#define BREAK_ON_PREFERRED_BUCKET_LIMIT
#ifdef DEBUG
@@ -174,8 +173,8 @@ VER::VER( INST *pinst )
: CZeroInit( sizeof( VER ) ),
m_pinst( pinst ),
m_fVERCleanUpWait( 2 ),
- m_msigRCECleanPerformedRecently( CSyncBasicInfo( _T( "m_msigRCECleanPerformedRecently" ) ) ),
- m_asigRCECleanDone( CSyncBasicInfo( _T( "m_asigRCECleanDone" ) ) ),
+ m_msigRCECleanPerformedRecently( CSyncBasicInfo( "m_msigRCECleanPerformedRecently" ) ),
+ m_asigRCECleanDone( CSyncBasicInfo( "m_asigRCECleanDone" ) ),
m_critRCEClean( CLockBasicInfo( CSyncBasicInfo( szRCEClean ), rankRCEClean, 0 ) ),
m_critBucketGlobal( CLockBasicInfo( CSyncBasicInfo( szBucketGlobal ), rankBucketGlobal, 0 ) ),
#ifdef VERPERF
@@ -188,6 +187,8 @@ VER::VER( INST *pinst )
(INT)UlParam(pinst, JET_paramVersionStoreTaskQueueMax),
ctasksPerBatchMaxDefault,
ctasksBatchedMaxDefault ),
+ m_fAboveMaxTransactionSize( fFalse ),
+ m_trxOldestRCE( trxMin ),
m_cresBucket( pinst )
{
@@ -1217,7 +1218,29 @@ INLINE VOID RCE::SetPrcePrevOfNode( RCE * prce )
Assert( FAssertRwlHashAsWriter_() );
Assert( prceNil == prce
|| RceidCmp( m_rceid, prce->Rceid() ) > 0 );
- m_prcePrevOfNode = prce;
+#ifdef DEBUG
+ if ( prce )
+ {
+ const BOOL fPrevRCEIsDelete = ( operFlagDelete == prce->m_oper && !prce->FMoved() );
+ if ( fPrevRCEIsDelete )
+ {
+ switch ( m_oper )
+ {
+ case operInsert:
+ case operPreInsert:
+ case operWriteLock:
+ // these are the only valid operations after a delete
+ break;
+
+ default:
+ {
+ Assert( m_fRolledBack );
+ }
+ }
+ }
+ }
+#endif
+ m_prcePrevOfNode = prce;
}
@@ -1758,6 +1781,10 @@ ERR VER::ErrVERICreateRCE(
}
Call( ErrVERIAllocateRCE( cbNewRCE, &prce, uiHashConcurrentOp ) );
+ if ( m_trxOldestRCE == trxMin )
+ {
+ m_trxOldestRCE = trxBegin0;
+ }
#ifdef DEBUG
if ( !PinstFromIfmp( pfcb->Ifmp() )->m_plog->FRecovering() )
@@ -4412,11 +4439,11 @@ ERR VER::ErrVERCheckTransactionSize( PIB * const ppib )
ERR err = JET_errSuccess;
if ( m_fAboveMaxTransactionSize )
{
- UpdateCachedTrxOldest( m_pinst );
+ VERSignalCleanup();
// If this is the oldest transaction and the version store is too
// full, return an error
- if ( ppib->trxBegin0 == TrxOldestCached( m_pinst ) )
+ if ( TrxCmp( ppib->trxBegin0, m_trxOldestRCE ) <= 0 )
{
const BOOL fCleanupWasRun = m_msigRCECleanPerformedRecently.FWait( cmsecAsyncBackgroundCleanup );
@@ -5157,8 +5184,19 @@ LOCAL VOID VERIFreeExt( PIB * const ppib, FCB *pfcb, PGNO pgnoFirst, CPG cpg )
const BOOL fCleanUpStateSavedSavedSaved = FOSSetCleanupState( fFalse );
- (VOID)ErrSPFreeExt( pfucb, pgnoFirst, cpg, "VerFreeExt" );
-
+ // Free extent only only after logging extent freed. If not, we might not capture the fact that these pages need to be reconciled if in required range and page is in dbtimeRevert.
+ // We will also mark the extent empty to avoid re-capturing page preimage.
+ err = ErrSPCaptureSnapshot( pfucb, pgnoFirst, cpg, fTrue );
+
+ if ( err >= JET_errSuccess )
+ {
+ (VOID)ErrSPFreeExt( pfucb, pgnoFirst, cpg, "VerFreeExt" );
+ }
+ else
+ {
+ SPReportSpaceLeak( pfucb, err, pgnoFirst, cpg, "VerFreeExt" );
+ }
+
// Restore cleanup checking
FOSSetCleanupState( fCleanUpStateSavedSavedSaved );
@@ -5787,10 +5825,10 @@ ERR VER::ErrVERICleanOneRCE( RCE * const prce )
VERIWaitForTasks( this, pfcbT, fFalse, fTrue );
- // bugfix (#45382): May have outstanding moved RCE's
+ // Processing of delta RCEs may have created flagDelete/writeLock RCEs after operTableDelete.
Assert( pfcbT->PrceOldest() == prceNil
- || ( pfcbT->PrceOldest()->Oper() == operFlagDelete
- && pfcbT->PrceOldest()->FMoved() ) );
+ || pfcbT->PrceOldest()->Oper() == operFlagDelete
+ || pfcbT->PrceOldest()->Oper() == operWriteLock );
VERNullifyAllVersionsOnFCB( pfcbT );
pfcbT->PrepareForPurge( fFalse );
@@ -5978,6 +6016,37 @@ ERR RCE::ErrPrepareToDeallocate( TRX trxOldest )
FCB * const pfcb = prce->Pfcb();
ENTERCRITICALSECTION enterCritFCBRCEList( &( pfcb->CritRCEList() ) );
+ // Except for recovery, this should be the HEAD RCE for this node. Recovery can
+ // allocate RCEs out of order because of deferred RCEs, so make sure to still clean
+ // them up in order.
+ Assert( PinstFromIfmp( m_ifmp )->FRecovering() || m_prcePrevOfNode == NULL );
+ if ( PinstFromIfmp( m_ifmp )->FRecovering() )
+ {
+ RCE *prceFirst = this;
+ // With Delta RCEs, you can have uncommitted delta RCEs preceding it, so let them be.
+ while ( prceFirst->Oper() != operDelta && prceFirst->Oper() != operDelta64 && prceFirst->m_prcePrevOfNode != NULL )
+ {
+ Assert( prceFirst->m_prcePrevOfNode->m_prceNextOfNode == prceFirst );
+ prceFirst = prceFirst->m_prcePrevOfNode;
+ }
+
+ while ( prceFirst != this )
+ {
+ RCE *prceNext = prceFirst->PrceNextOfNode();
+
+ ASSERT_VALID( prceFirst );
+ Assert( !prceFirst->FOperNull() );
+ // Only deferrable oper's like FlagDelete/Replace should end up out-of-order
+ Assert( prceFirst->Oper() == operFlagDelete || prceFirst->Oper() == operReplace );
+ Assert( prceFirst->FFullyCommitted() );
+ Assert( TrxCmp( prceFirst->TrxCommitted(), trxOldest ) < 0 );
+
+ VERINullifyCommittedRCE( prceFirst );
+
+ prceFirst = prceNext;
+ }
+ }
+
do
{
RCE *prceNext;
@@ -6138,6 +6207,11 @@ ERR VER::ErrVERIRCEClean( const IFMP ifmp )
const TRX trxRCECommitted = prce->TrxCommitted();
BOOL fCleanable = fFalse;
+ if ( !fCleanOneDb )
+ {
+ m_trxOldestRCE = fFullyCommitted ? trxRCECommitted : prce->TrxBegin0();
+ }
+
if ( trxMax == trxOldest )
{
// trxOldest may no longer be trxMax. if so we may not be able to
@@ -6184,6 +6258,13 @@ ERR VER::ErrVERIRCEClean( const IFMP ifmp )
//
Assert( fFalse );
}
+
+ // If we are only cleaning one database, and this RCE belongs to another one and we already
+ // skipped the first RCE in the node chain, skip this one also.
+ if ( fCleanable && fCleanOneDb && prce->Ifmp() != ifmp && prce->FPastVersionsOfNode() )
+ {
+ fCleanable = fFalse;
+ }
}
if ( !fCleanable )
@@ -6333,6 +6414,7 @@ ERR VER::ErrVERIRCEClean( const IFMP ifmp )
}
else
{
+ m_trxOldestRCE = trxMin;
Assert( pbucketNil == m_pbucketGlobalTail );
}
m_critBucketGlobal.Leave();
diff --git a/dev/ese/src/eseutil/_edbutil.hxx b/dev/ese/src/eseutil/_edbutil.hxx
index 8c7e633b..be0c87b5 100644
--- a/dev/ese/src/eseutil/_edbutil.hxx
+++ b/dev/ese/src/eseutil/_edbutil.hxx
@@ -5,13 +5,6 @@
#include
#include
#include
-#pragma prefast(push)
-#pragma prefast(disable:26006, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:26007, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28718, "Dont bother us with tchar, someone else owns that.")
-#pragma prefast(disable:28726, "Dont bother us with tchar, someone else owns that.")
-#include
-#pragma prefast(pop)
#include "os.hxx"
diff --git a/dev/ese/src/eseutil/dbspacedump.cxx b/dev/ese/src/eseutil/dbspacedump.cxx
index 31cca67e..64864058 100644
--- a/dev/ese/src/eseutil/dbspacedump.cxx
+++ b/dev/ese/src/eseutil/dbspacedump.cxx
@@ -1466,8 +1466,7 @@ JET_ERR ErrPrintField(
if ( pBTStats->pBasicCatalog->pSpaceHints )
{
WCHAR wszSpaceHintsGrbits[12];
- const JET_ERR err = ErrOSStrCbFormatW( wszSpaceHintsGrbits, sizeof(wszSpaceHintsGrbits), L"0x%x", pBTStats->pBasicCatalog->pSpaceHints->grbit );
- assert( JET_errSuccess == err );
+ OSStrCbFormatW( wszSpaceHintsGrbits, sizeof(wszSpaceHintsGrbits), L"0x%x", pBTStats->pBasicCatalog->pSpaceHints->grbit );
assert( rgSpaceFields[eField].cchFieldSize >= (ULONG)LOSStrLengthW( wszSpaceHintsGrbits ) );
wprintf( L"%ws%ws", WszFillBuffer( L' ', rgSpaceFields[eField].cchFieldSize - LOSStrLengthW( wszSpaceHintsGrbits ) ), wszSpaceHintsGrbits );
}
@@ -1784,10 +1783,8 @@ JET_ERR ErrSpaceDumpCtxSetFields(
wszTemp[0] = L'\0';
for( ULONG eField = 1; eField < sizeof(rgSpaceFields)/sizeof(rgSpaceFields[0]); eField++ )
{
- ULONG ret = StringCbCatW( (WCHAR*)wszTemp, cb, rgSpaceFields[eField].wszField );
- assert( 0 == ret );
- ret = StringCbCatW( (WCHAR*)wszTemp, cb, L"," );
- assert( 0 == ret );
+ OSStrCbAppendW( wszTemp, cb, rgSpaceFields[eField].wszField );
+ OSStrCbAppendW( wszTemp, cb, L"," );
}
wszFields = wszTemp;
}
@@ -1924,7 +1921,7 @@ JET_ERR ErrSpaceDumpCtxSetOptions(
// We only allow 1 char + NUL separators, likely it was wrong.
assert( wszSeparator[0] != L'\0' );
assert( wszSeparator[1] == L'\0' );
- if ( S_OK != StringCbCopyW( pespCtx->rgwchSep, sizeof(pespCtx->rgwchSep), wszSeparator ) )
+ if ( JET_errSuccess > ErrOSStrCbCopyW( pespCtx->rgwchSep, sizeof(pespCtx->rgwchSep), wszSeparator ) )
{
assertSz( fFalse, "Huh?" );
return ErrERRCheck( JET_errInvalidParameter );
diff --git a/dev/ese/src/eseutil/eseutil.cxx b/dev/ese/src/eseutil/eseutil.cxx
index 2e3ca9be..3af80032 100644
--- a/dev/ese/src/eseutil/eseutil.cxx
+++ b/dev/ese/src/eseutil/eseutil.cxx
@@ -18,13 +18,6 @@
#include "esefile.hxx"
#undef UNICODE // esefile.hxx enables UNICODE
-#pragma prefast(push)
-#pragma prefast(disable:28196, "Do not bother us with strsafe, someone else owns that.")
-#pragma prefast(disable:28205, "Do not bother us with strsafe, someone else owns that.")
-#include
-#pragma prefast(pop)
-
-
#ifndef ESENT
#include
#define ESEBCLI2_DLL_NAME L"ESEBCLI2.DLL"
@@ -46,6 +39,18 @@
ESESHADOW_LOCAL_DEFERRED_DLL_STATE
#endif
+// Base product name and version numbers reported by eseutil.
+#ifdef ESENT
+#define ESEUTIL_PRODUCT_NAME L"Windows(R)"
+#define ESEUTIL_PRODUCT_MAJOR VER_PRODUCTMAJORVERSION
+#define ESEUTIL_PRODUCT_MINOR VER_PRODUCTMINORVERSION
+#else
+#define ESEUTIL_PRODUCT_NAME L"Exchange Server"
+#define ESEUTIL_PRODUCT_MAJOR PRODUCT_MAJOR
+#define ESEUTIL_PRODUCT_MINOR PRODUCT_MINOR
+#endif
+
+
// In fake recovery without undo, we set the grbit for JET_bitRecoveryWithoutUndo, but
// then the our callback control decides to do undo after all, unless the "/u" option
// was passed.
@@ -147,11 +152,7 @@ LOCAL const WCHAR * const wszUsageErr21 = L"Usage Error: Config store spec n
LOCAL const WCHAR * const wszUsageErr22 = L"Usage Error: Invalid log generation range specification.";
-#ifdef ESENT
-LOCAL const WCHAR * const wszHelpDesc1 = L"DESCRIPTION: Database utilities for the Extensible Storage Engine for Microsoft(R) Windows(R).";
-#else // !ESENT
-LOCAL const WCHAR * const wszHelpDesc1 = L"DESCRIPTION: Database utilities for the Extensible Storage Engine for Microsoft(R) Exchange Server.";
-#endif // ESENT
+LOCAL const WCHAR * const wszHelpDesc1 = L"DESCRIPTION: Database utilities for the Extensible Storage Engine for Microsoft(R) " ESEUTIL_PRODUCT_NAME L".";
LOCAL const WCHAR * const wszHelpSyntax = L"MODES OF OPERATION:";
LOCAL const WCHAR * const wszHelpModes1 = L" Defragmentation: %s /d [options]";
LOCAL const WCHAR * const wszHelpModes2 = L" Recovery: %s /r [options]";
@@ -213,16 +214,8 @@ LOCAL WCHAR *GetCurArg();
LOCAL VOID EDBUTLPrintLogo( void )
{
- WCHAR wszVersion[16];
-
-#ifdef ESENT
- StringCbPrintfW( wszVersion, sizeof(wszVersion), L"%d.%d", VER_PRODUCTMAJORVERSION, VER_PRODUCTMINORVERSION );
- wprintf( L"Extensible Storage Engine Utilities for Microsoft(R) Windows(R)%c", wchNewLine );
-#else // !ESENT
- StringCbPrintfW( wszVersion, sizeof(wszVersion), L"%hs.%hs", PRODUCT_MAJOR, PRODUCT_MINOR );
- wprintf( L"Extensible Storage Engine Utilities for Microsoft(R) Exchange Server%c", wchNewLine );
-#endif // ESENT
- wprintf( L"Version %s%c", wszVersion, wchNewLine );
+ wprintf( L"Extensible Storage Engine Utilities for Microsoft(R) %s%c", ESEUTIL_PRODUCT_NAME, wchNewLine );
+ wprintf( L"Version %hs.%hs%c", ESEUTIL_PRODUCT_MAJOR, ESEUTIL_PRODUCT_MINOR, wchNewLine );
wprintf( L"Copyright (c) Microsoft Corporation.\nLicensed under the MIT License.%c", wchNewLine );
wprintf( L"%c", wchNewLine );
}
@@ -2112,11 +2105,17 @@ LOCAL BOOL FEDBUTLParseRepair( _In_ PCWSTR arg, UTILOPTS *popts )
LOCAL VOID EDBUTLGetBaseName( _In_ PCWSTR const wszLogfile, __out_ecount(4) WCHAR * const wszBaseName )
{
WCHAR wszNameT[_MAX_FNAME+1];
+ ERR errT;
assert( wszBaseName != NULL );
_wsplitpath_s( wszLogfile, NULL, 0, NULL, 0, wszNameT, _countof(wszNameT), NULL, 0);
- StringCbCopyW( wszBaseName, 4 * sizeof(WCHAR), wszNameT );
+ errT = ErrOSStrCbCopyW( wszBaseName, 4 * sizeof(WCHAR), wszNameT );
+ // We're not telling the truth about how big wszBaseName is, we're instead artificially
+ // shortening it to 4 WCHARs in order to only copy 4 WCHARs from wszNameT. We would
+ // use OSSStrCbCopyNW(), if it existed. The end result is that we might get success
+ // back and we might get buffer too small, depending on the length of wszNameT
+ assert( errT == JET_errSuccess || errT == JET_errBufferTooSmall );
}
LOCAL BOOL FEDBUTLBaseNameOnly( const WCHAR * const wszName )
@@ -2404,7 +2403,7 @@ LOCAL BOOL FEDBUTLParseDump( _In_ PCWSTR arg, UTILOPTS *popts )
{
const size_t cchSzNode = 256;
WCHAR wszNode[cchSzNode];
- StringCbCopyW( wszNode, sizeof(wszNode), arg+2 );
+ OSStrCbCopyW( wszNode, sizeof(wszNode), arg+2 );
INT dbid = 0;
INT pgno = 0;
@@ -2480,7 +2479,7 @@ LOCAL BOOL FEDBUTLParseDump( _In_ PCWSTR arg, UTILOPTS *popts )
{
const size_t cchSzLogRange = 256;
WCHAR wszLogRange[cchSzLogRange];
- StringCbCopyW( wszLogRange, sizeof( wszLogRange ), arg + 2 );
+ OSStrCbCopyW( wszLogRange, sizeof( wszLogRange ), arg + 2 );
LONG lgenStart = 0;
LONG lgenEnd = 0;
@@ -3408,12 +3407,12 @@ LOCAL JET_ERR ErrEDBUTLBackupAndInstateDB(
_wsplitpath_s( popts->wszSourceDB, wszDrive, _countof(wszDrive), wszDir, _countof(wszDir), NULL, 0, NULL, 0 );
_wmakepath_s( wszSourceDB, _countof(wszSourceDB), wszDrive, wszDir, NULL, NULL );
- StringCbCatW( wszSourceDB, sizeof(wszSourceDB), wfd.cFileName );
+ OSStrCbAppendW( wszSourceDB, sizeof(wszSourceDB), wfd.cFileName );
FindClose( hFind );
}
else
{
- StringCbCopyW( wszSourceDB, sizeof(wszSourceDB), popts->wszSourceDB );
+ OSStrCbCopyW( wszSourceDB, sizeof(wszSourceDB), popts->wszSourceDB );
}
// Make backup before instating, if requested.
@@ -3671,7 +3670,7 @@ ERR ErrPrintESEBCLI2Error ( HRESULT hr, HRESULT hrGLE, HMODULE hESEBCLI2 )
wszFinalMsg = (WCHAR *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, cbFinalMsg );
if ( wszFinalMsg )
{
- StringCbPrintfW( wszFinalMsg, cbFinalMsg, (WCHAR *)lpMsgBuf, hrGLE );
+ OSStrCbFormatW( wszFinalMsg, cbFinalMsg, (WCHAR *)lpMsgBuf, hrGLE );
LocalFree( lpMsgBuf );
}
else
@@ -3746,7 +3745,7 @@ WCHAR * WszCopy( const WCHAR * wsz )
if ( ( wszCopy = (WCHAR *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, cb ) ) == NULL )
return(NULL);
- StringCbCopyW( wszCopy, cb, wsz );
+ OSStrCbCopyW( wszCopy, cb, wsz );
return( wszCopy );
}
@@ -3758,7 +3757,7 @@ void FormatErrorInfoString(
const JET_ERRINFOBASIC_W * perrinfo )
{
Assert( szFormatted[0] == '\0' );
- (void)ErrOSStrCbFormatA( szFormatted, cbFormatted, "err = %d (%ws", err, wszErrStrings ? wszErrStrings : L"unknown, unknown" );
+ OSStrCbFormatA( szFormatted, cbFormatted, "err = %d (%ws", err, wszErrStrings ? wszErrStrings : L"unknown, unknown" );
// Truncate off the ", " to get the constant name only.
CHAR * const szBeginErrExplanation = strchr( szFormatted, ',' );
Assert( szBeginErrExplanation ); // implies we didn't get the , before we potentially truncated!?
@@ -3770,7 +3769,7 @@ void FormatErrorInfoString(
#ifdef DEBUG
if ( perrinfo && perrinfo->lSourceLine != 0 )
{
- (void)ErrOSStrCbFormatA( szFormatted + strlen(szFormatted), cbFormatted - strlen(szFormatted),
+ OSStrCbFormatA( szFormatted + strlen(szFormatted), cbFormatted - strlen(szFormatted),
" - %ws:%d", perrinfo->rgszSourceFile, perrinfo->lSourceLine );
}
#endif
@@ -3918,7 +3917,7 @@ LOCAL VOID DBUTLIDumpRestoreEnv( RESTORE_ENVIRONMENT * pREnv, INT cDesc = 0 )
PrintField( L"", cDesc, NULL );
- StringCbPrintfW( wszBuffer, sizeof( wszBuffer ), L"%d database(s)", pREnv->m_cDatabases );
+ OSStrCbFormatW( wszBuffer, sizeof( wszBuffer ), L"%d database(s)", pREnv->m_cDatabases );
PrintField( L"Databases:", cDesc, wszBuffer );
assert ( pREnv->m_wszDatabaseDisplayName || 0 == pREnv->m_cDatabases);
@@ -3939,7 +3938,7 @@ LOCAL VOID DBUTLIDumpRestoreEnv( RESTORE_ENVIRONMENT * pREnv, INT cDesc = 0 )
PrintField( L"Database Name:", cDesc, pREnv->m_wszDatabaseDisplayName[iDb] );
// like: 6B29FC40-CA47-1067-B31D-00DD010662DA
- StringCbPrintfW( guidStr, sizeof( guidStr ),
+ OSStrCbFormatW( guidStr, sizeof( guidStr ),
L"%08X-%04X-%04X-%08X%08X",
guid.Data1, guid.Data2, guid.Data3,
*(DWORD *)&guid.Data3,*( 1 + (DWORD *)&guid.Data3 ) );
@@ -3980,7 +3979,7 @@ LOCAL VOID DBUTLIDumpRestoreEnv( RESTORE_ENVIRONMENT * pREnv, INT cDesc = 0 )
// in restore.env at parsing point (HrESERestoreOpenFile)
// For now, we will display the Store defaults as this is
// the only client using the eseback2/esebcli2 anyway
- StringCbPrintfW( wszBuffer, sizeof( wszBuffer ), L"%s%08X.log - %s%08X.log",
+ OSStrCbFormatW( wszBuffer, sizeof( wszBuffer ), L"%s%08X.log - %s%08X.log",
pREnv->m_wszLogBaseName,
pREnv->m_ulGenLow,
pREnv->m_wszLogBaseName,
@@ -3990,7 +3989,7 @@ LOCAL VOID DBUTLIDumpRestoreEnv( RESTORE_ENVIRONMENT * pREnv, INT cDesc = 0 )
{
assert ( 0 == pREnv->m_ulGenLow );
assert ( 0 == pREnv->m_ulGenHigh );
- StringCbPrintfW( wszBuffer, sizeof( wszBuffer ), L"no log files restored");
+ OSStrCbFormatW( wszBuffer, sizeof( wszBuffer ), L"no log files restored");
}
PrintField( L"Log files range:", cDesc, wszBuffer );
@@ -4003,7 +4002,7 @@ LOCAL VOID DBUTLIDumpRestoreEnv( RESTORE_ENVIRONMENT * pREnv, INT cDesc = 0 )
PrintField( L"Recover Status:", cDesc, rwszRecoverStatus [ status ] );
- StringCbPrintfW( wszBuffer, sizeof( wszBuffer ), L"0x%08X", pREnv->m_hrLastRecover);
+ OSStrCbFormatW( wszBuffer, sizeof( wszBuffer ), L"0x%08X", pREnv->m_hrLastRecover);
PrintField( L"Recover Error:", cDesc, wszBuffer );
PrintField( L"Recover Time:", cDesc, ( 0 != pREnv->m_timeLastRecover ? _wctime( &pREnv->m_timeLastRecover ) : L"" ) );
@@ -5315,7 +5314,7 @@ LOCAL JET_ERR ErrEDBUTLCheckLogStream( JET_INSTANCE* pInst, UTILOPTS* pOpts )
// file name (with wild card)
WCHAR wszFName[ _MAX_PATH + 1 ];
Call( JetGetSystemParameterW( *pInst, JET_sesidNil, JET_paramBaseName, NULL, wszFName, sizeof( wszFName ) ) );
- StringCchCatW( wszFName, _countof( wszFName ), L"*" );
+ OSStrCbAppendW( wszFName, sizeof( wszFName ), L"*" );
//================================
// drive and dir
@@ -5388,7 +5387,7 @@ void PushEseutilArgTrace( INT argc, __in_ecount(argc) LPWSTR argv[] )
{
CHAR * szT = szEseutilCmd;
- (void)ErrOSStrCbFormatA( szT, cbAllArgs, "Command: \"" ); // 5 spaces is _perfect_. Excercise to reader as to why.
+ OSStrCbFormatA( szT, cbAllArgs, "Command: \"" ); // 5 spaces is _perfect_. Excercise to reader as to why.
size_t cbUsed = strlen( szT );
szT += cbUsed;
cbAllArgs -= cbUsed;
@@ -5396,7 +5395,7 @@ void PushEseutilArgTrace( INT argc, __in_ecount(argc) LPWSTR argv[] )
for( INT iarg = 0; iarg < argc; iarg++ )
{
// Not sure if MBCS can expand this, but left buffer anyways, may truncate but we'd survive.
- (void)ErrOSStrCbFormatA( szT, cbAllArgs, "%ws ", argv[iarg] );
+ OSStrCbFormatA( szT, cbAllArgs, "%ws ", argv[iarg] );
cbUsed = strlen( szT );
szT += cbUsed;
cbAllArgs -= cbUsed;
@@ -5404,7 +5403,7 @@ void PushEseutilArgTrace( INT argc, __in_ecount(argc) LPWSTR argv[] )
if ( argc )
{
// if we had any args wipe out the last space with the end quote.
- (void)ErrOSStrCbFormatA( szT - 1, cbAllArgs + 1, "\"" );
+ OSStrCbFormatA( szT - 1, cbAllArgs + 1, "\"" );
}
JET_TESTHOOKTRACETESTMARKER mark = { sizeof(mark), szEseutilCmd, 1 };
JetTestHook( opTestHookTraceTestMarker, &mark );
diff --git a/dev/ese/src/inc/_bf.hxx b/dev/ese/src/inc/_bf.hxx
index 5678969d..cba7f6d1 100644
--- a/dev/ese/src/inc/_bf.hxx
+++ b/dev/ese/src/inc/_bf.hxx
@@ -277,7 +277,7 @@ struct BF // BF -- IFMP/PGNO buffer
RCE* prceUndoInfoNext; // Undo Info chain
- void* pvIOContext; // I/O context (in practice, an IOREQ)
+ void* pvIOContext; // I/O context (in practice, an IOREQ, async IO only)
// 144 B /////////////////////////////////////////////////////////////////////////////////////
@@ -314,7 +314,7 @@ struct BF // BF -- IFMP/PGNO buffer
CSXWLatch sxwl; // S/X/W Latch protecting this BF state and
// its associated cached page
- void* pvIOContext; // I/O context (in practice, an IOREQ)
+ void* pvIOContext; // I/O context (in practice, an IOREQ, async IO only)
IFMP ifmp; // IFMP of this cached page
PGNO pgno; // PGNO of this cached page
@@ -601,6 +601,8 @@ void BFIFTLTerm();
// BF tracing
+void BFICacheTraceSamplingInit( const ULONG ulSamplingRatio );
+
INLINE void BFITraceResMgrInit(
const INT K,
const double csecCorrelatedTouch,
@@ -1532,6 +1534,12 @@ void BFIReleaseIOContext( PBF pbf, void* const pvIOContext );
void BFISetIOContext( PBF pbf, void* const pvIOContextNew );
void BFIResetIOContext( PBF pbf );
+void BFISetAsyncIOContext( _In_ const PBF pbf, _In_ void* const pvIOContextNew );
+void BFIResetAsyncIOContext( _In_ const PBF pbf );
+TICK TickBFISyncIOContextStartTime();
+void BFISetSyncIOContext( _In_ const PBF pbf );
+void BFIResetSyncIOContext( _In_ const PBF pbf );
+
BOOL FBFIIsIOHung( PBF pbf );
BYTE PctBFIIsIOHung( PBF pbf, void* const pvIOContext );
ERR ErrBFIFlushPendingStatus( PBF pbf );
@@ -1540,15 +1548,6 @@ void BFIPrepareReadPage( PBF pbf );
void BFIPrepareWritePage( PBF pbf );
void BFISyncRead( PBF pbf, const OSFILEQOS qosIoPriorities, const TraceContext& tc );
-void BFISyncReadHandoff( const ERR err,
- IFileAPI *const pfapi,
- const FullTraceContext& tc,
- const OSFILEQOS grbitQOS,
- const QWORD ibOffset,
- const DWORD cbData,
- const BYTE* const pbData,
- const PBF pbf,
- void* const pvIOContext );
void BFISyncReadComplete( const ERR err,
IFileAPI *const pfapi,
const OSFILEQOS grbitQOS,
@@ -1590,15 +1589,6 @@ void BFIAsyncReadTempComplete( const ERR err,
const IFMP ifmp);
ERR ErrBFISyncWrite( PBF pbf, const BFLatchType bfltHave, OSFILEQOS qos, const TraceContext& tc );
-void BFISyncWriteHandoff( const ERR err,
- IFileAPI *const pfapi,
- const FullTraceContext& tc,
- const OSFILEQOS grbitQOS,
- const QWORD ibOffset,
- const DWORD cbData,
- const BYTE* const pbData,
- const PBF pbf,
- void* const pvIOContext );
void BFISyncWriteComplete( const ERR err,
IFileAPI *const pfapi,
const FullTraceContext& tc,
diff --git a/dev/ese/src/inc/_jet.hxx b/dev/ese/src/inc/_jet.hxx
index b729e2c3..280f6b42 100644
--- a/dev/ese/src/inc/_jet.hxx
+++ b/dev/ese/src/inc/_jet.hxx
@@ -462,7 +462,7 @@ typedef CAutoIWSZ< 90 > CAutoWSZPATH;
{ \
err = (func); \
} \
- EXCEPT( GrbitParam( JET_paramExceptionAction ) != JET_ExceptionNone ? ExceptionFail( _T( "API" ) ) : efaContinueSearch ) \
+ EXCEPT( GrbitParam( JET_paramExceptionAction ) != JET_ExceptionNone ? ExceptionFail( "API" ) : efaContinueSearch ) \
{ \
AssertPREFIX( !"This code path should be impossible (the exception-handler should have terminated the process)." ); \
err = ErrERRCheck( JET_errInternalError ); \
@@ -490,9 +490,9 @@ typedef CAutoIWSZ< 90 > CAutoWSZPATH;
TRY \
{ \
err = (func); \
- OSTrace( JET_tracetagAPI, OSFormat( "End %s with error %d (0x%x)", _T( #func ), err, err ) ); \
+ OSTrace( JET_tracetagAPI, OSFormat( "End %s with error %d (0x%x)", #func, err, err ) ); \
} \
- EXCEPT( GrbitParam( JET_paramExceptionAction ) != JET_ExceptionNone ? ExceptionFail( _T( #func ) ) : efaContinueSearch ) \
+ EXCEPT( GrbitParam( JET_paramExceptionAction ) != JET_ExceptionNone ? ExceptionFail( #func ) : efaContinueSearch ) \
{ \
AssertPREFIX( !"This code path should be impossible (the exception-handler should have terminated the process)." ); \
err = ErrERRCheck( JET_errInternalError ); \
@@ -519,7 +519,7 @@ typedef CAutoIWSZ< 90 > CAutoWSZPATH;
OSEventTrace( _etguidApiCall_Start, 1, &ulTraceApiId ); \
CLockDeadlockDetectionInfo::GetApiEntryState(&cDisableDeadlockCheck, &cDisableOwnershipCheck, &cLocks); \
const JET_ERR err = (func); \
- OSTrace( JET_tracetagAPI, OSFormat( "End %s with error %d (0x%x)", _T( #func ), err, err ) ); \
+ OSTrace( JET_tracetagAPI, OSFormat( "End %s with error %d (0x%x)", #func, err, err ) ); \
AssertRTL( err > -65536 && err < 65536 ); \
fDisableLockCheck ? CLockDeadlockDetectionInfo::DisableLockCheckOnApiExit() : 0;\
CLockDeadlockDetectionInfo::AssertCleanApiExit(cDisableDeadlockCheck, cDisableOwnershipCheck, cLocks); \
diff --git a/dev/ese/src/inc/_osu/fileu.hxx b/dev/ese/src/inc/_osu/fileu.hxx
index add403cc..2aa6ed89 100644
--- a/dev/ese/src/inc/_osu/fileu.hxx
+++ b/dev/ese/src/inc/_osu/fileu.hxx
@@ -28,6 +28,7 @@ typedef struct tagDbHeaderReader
{
ShadowedHeaderRequest shadowedHeaderRequest; // in
const WCHAR* wszFileName; // in
+ ULONG filetype; // in
BYTE* pbHeader; // in
DWORD cbHeader; // in
LONG ibPageSize; // in
@@ -58,6 +59,7 @@ ERR ErrUtilReadShadowedHeader(
const INST* const pinst,
IFileSystemAPI* const pfsapi,
const WCHAR* const wszFilePath,
+ _In_ const ULONG filetype,
__out_bcount( cbHeader ) BYTE* pbHeader,
const DWORD cbHeader,
const LONG ibPageSize,
@@ -69,6 +71,7 @@ ERR ErrUtilReadShadowedHeader(
const INST* const pinst,
IFileSystemAPI* const pfsapi,
IFileAPI* const pfapi,
+ _In_ const ULONG filetype,
__out_bcount( cbHeader ) BYTE* pbHeader,
const DWORD cbHeader,
const LONG ibPageSize,
diff --git a/dev/ese/src/inc/_osu/syncu.hxx b/dev/ese/src/inc/_osu/syncu.hxx
index c62eeda1..8aadef7f 100644
--- a/dev/ese/src/inc/_osu/syncu.hxx
+++ b/dev/ese/src/inc/_osu/syncu.hxx
@@ -221,7 +221,7 @@ class CRITPOOL
~CRITPOOL( void );
CRITPOOL& operator=( CRITPOOL& ); // disallowed
- BOOL FInit( const LONG cThread, const INT rank, const _TCHAR* szName );
+ BOOL FInit( const LONG cThread, const INT rank, const CHAR* szName );
void Term( void );
CCriticalSection& Crit( const T* const pt );
@@ -260,7 +260,7 @@ CRITPOOL::~CRITPOOL( void )
// fTrue on success or fFalse on failure
template
-BOOL CRITPOOL::FInit( const LONG cThread, const INT rank, const _TCHAR* szName )
+BOOL CRITPOOL::FInit( const LONG cThread, const INT rank, const CHAR* szName )
{
// ensure that Term() was called or ErrInit() was never called
@@ -360,7 +360,7 @@ class RWLPOOL
~RWLPOOL( void );
RWLPOOL& operator=( RWLPOOL& ); // disallowed
- BOOL FInit( const LONG cThread, const LONG cbObjectSize, const INT rank, const _TCHAR* szName );
+ BOOL FInit( const LONG cThread, const LONG cbObjectSize, const INT rank, const CHAR* szName );
void Term( void );
CReaderWriterLock& Rwl( const VOID* const pObj );
@@ -398,7 +398,7 @@ INLINE RWLPOOL::~RWLPOOL( void )
// initializes the reader writer lock pool for use by cThread threads, returning
// fTrue on success or fFalse on failure
-INLINE BOOL RWLPOOL::FInit( const LONG cThread, const LONG cbObjectSize, const INT rank, const _TCHAR* szName )
+INLINE BOOL RWLPOOL::FInit( const LONG cThread, const LONG cbObjectSize, const INT rank, const CHAR* szName )
{
// ensure that Term() was called or ErrInit() was never called
diff --git a/dev/ese/src/inc/_space.hxx b/dev/ese/src/inc/_space.hxx
index 26137eac..e4e4d929 100644
--- a/dev/ese/src/inc/_space.hxx
+++ b/dev/ese/src/inc/_space.hxx
@@ -146,6 +146,18 @@ ERR ErrSPIOpenOwnExt(
FUCB *pfucb,
FUCB **ppfucbOE );
+ERR ErrSPIGetInfo(
+ FUCB *pfucb,
+ const PGNO pgnoHighest,
+ CPG *pcpgTotal,
+ CPG *pcpgReserved,
+ CPG *pcpgShelved,
+ INT *piext,
+ INT cext,
+ EXTENTINFO *rgext,
+ INT *pcextSentinelsRemaining,
+ CPRINTF * const pcprintf );
+
ERR ErrSPIGetExtentInfo(
_In_ const FUCB *pfucb,
_Out_ PGNO *ppgnoLast,
diff --git a/dev/ese/src/inc/bbtbuff.hxx b/dev/ese/src/inc/bbtbuff.hxx
new file mode 100644
index 00000000..8b25d598
--- /dev/null
+++ b/dev/ese/src/inc/bbtbuff.hxx
@@ -0,0 +1,1293 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+/************************************************************************************************************
+A BBT buffer is a data structure used to store tree operations on the BBT at intermediate levels of the tree.
+Each non-leaf (root & internal) page in a BBT has a BBT buffer. It has the following strucutre:
+1. Each BBT buffer comprises of multiple physically contiguous ESE pages.
+2. The first page of the BBT buffer is called the BBT root (or BBT base page). A portion of it is allocated
+ to hold the BBT buffer using a reserved tag. The rest is available for use by classic BT nodes for storing
+ key separators.
+3. The rest of the pages comprising the BBT buffer each contain 1 reserved tag that takes up all of the
+ available space on the page.
+3. All of this space is considered one logical buffer indexed by an offset starting from the BBT root.
+3. The BBT header is stored at offset 0 (i.e. at the begining of the BBT root).
+4. The rest of the space is used to store nodes in a SkipList structure.
+5. Each node in the skiplist stores a BBTBuffOpcode, KEY & DATA for the operation.
+6. The buffer is designed to be append-only. Each new operation on the tree results in adding a new node to
+ the buffer with the right opcode. E.g., a delete on a key will result in an insertion of bbtOpDelete with
+ the right key (and no data).
+
+The BBT buffer provides the following:
+1. It is sorted, allowing avg log(n) seek/insert/delete operations.
+2. It allows adding duplicate nodes, and provides a stable sort over the nodes. That is, the BBT buffer
+ guarantees that the insertion order of duplicate nodes is maintained by the sort. This means that
+ operations can be enumerated from oldest to latest.
+3. Provides facilities for bulk merge and deletion of nodes. This is used to 'evict' operations from the
+ top-level to lower levels of the BBT, as buffers get full.
+
+Layering and Responsibilities:
+1. Owns the physical format of the BBT buffer. Uses CPAGE to manage per-page format. Comparable to NODE.
+2. Also owns runtime interface to the buffer:
+ - Read APIs and Write APIs (non-transacted).
+ - The companion class BBTBuffWriter provides transacted APIs for writing, allowing redo through a trx log.
+ - Manages latches. Built on top of CSR latch APIs.
+ - Also handles currency for the buffer. This is comparable to the CSR interface.
+
+BBTBuff Latching policy:
+1. Base page must always be kept latched (caller must own this latch).
+2. Base page latch state when the BBTBuff is loaded is considered 'ground state.'
+3. Any latches obtained during any BBTBuff operation are kept latched at 'ground state'
+ for the lifetime of BBTBuff or until Release() is called.
+4. For modify operations, latches will be upgraded to write for the duration of the operation,
+ then downgraded to ground state when the operation is complete.
+5. ErrUpgradeToWriteMode() means that the ground state is upgraded to latchWrite alongwith the base page latch,
+ so after that, any latches acquired will be kept at latchWrite state.
+6. Downgrade() can be called to bring the ground state back to read or RIW. Base page latch will be
+ downgraded accordingly.
+7. Latch order: Base page must be latched/upgraded first. The rest of the pages can be latched in any order.
+
+Above policy is used in three different ways:
+1. Read-only: Simplest form. All latches stay at latchRead.
+2. RIW: BBTBuff is loaded with base page at latchRIW. Any modify operations will temporarily
+ upgrade to latchWrite, and then downgrades latches back to latchRIW. Theoretically, this
+ can also be done starting with latchRead, but latch conflicts could cause us to lose
+ all latches and fail (BBTBuff handles this case properly, and marks itself unusable).
+ However, we always start with RIW for a write operation.
+3. Write: ErrUpgradeToWriteMode() is used to keep BBTBuff in latchWrite state.
+
+************************************************************************************************************/
+
+// Maximum levels supported by the skiplist
+// 16 allows 64k nodes to be stored in the list with
+// list operations achieving average case O(logn) performance.
+constexpr int MAX_LEVELS = 16;
+
+// This is the reserved itag on every BBTBuff root page. Must be the second reserved itag.
+constexpr int itagReservedBBTBuffRoot = 1;
+
+struct BBTBuffFormat
+{
+ int cbCPAGE; // size of the underlying physical page (CPAGE).
+ int cbBBTRoot; // size of the BBT root, amount of space allocated to the BBT buffer on the BBT base page.
+ int cpgInBBTBuff; // total number of physical pages that comprise a BBT superpage.
+};
+
+// UA_TODO: magic numbers, tune later
+extern constexpr __declspec( selectany ) BBTBuffFormat BBTBUFF_FORMAT_CONSTANTS[] =
+{
+ { 4 * 1024, 1 * 1024, 32 }, // 128k BBTBuff
+ { 8 * 1024, 4 * 1024, 16 }, // 128k
+ { 16 * 1024, 8 * 1024, 16 }, // 256k
+ { 32 * 1024, 24 * 1024, 16 }, // 512k
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// BEGIN persisted structures
+#include
+
+PERSISTED
+enum BBTBuffVersion : BYTE
+{
+ bbtvInvalid = 0,
+ bbtvInitial = 1,
+
+ bbtvMax = 255
+};
+
+PERSISTED
+enum BBTBuffOpcode : BYTE
+{
+ bbtOpNone = 0,
+ bbtOpInsert = 1,
+ bbtOpUpdate = 2,
+ bbtOpDelete = 3,
+ bbtOpEscrowUpdate = 4,
+ bbtOpUpsert = 5,
+
+ bbtOpMax = 15,
+};
+
+// SkipListNode structure:
+// | Hdr | m_cbKey+Flags | m_cbData | rgLinks[ m_iLevel + 2 ] | Key | Data |
+// Bytes: 0 2 DVC-4 6 11->51 IbKey()+m_CbKey IbData()+m_cbData
+// D = fDeleted
+// V = fVersioned
+// C = Compressed
+// - = Reserved
+// iLevel+2 because level0 node stores prev0 and next0 link
+
+// Stored on the high bits of SkipListNode::m_cbKey
+PERSISTED
+enum SkipListNodeFlags : USHORT
+{
+ fSLNNone = 0,
+ fSLNDeleted = 0x01,
+ fSLNVersioned = 0x02,
+ fSLNCompressed = 0x04,
+};
+
+inline SkipListNodeFlags operator|( SkipListNodeFlags a, SkipListNodeFlags b )
+{
+ return static_cast( static_cast( a ) | static_cast( b ) );
+}
+
+inline SkipListNodeFlags operator&( SkipListNodeFlags a, SkipListNodeFlags b )
+{
+ return static_cast( static_cast( a ) & static_cast( b ) );
+}
+
+inline SkipListNodeFlags operator~( SkipListNodeFlags a )
+{
+ return static_cast( ~static_cast( a ) );
+}
+
+PERSISTED
+class SkipListLink
+{
+ friend class SkipListLinkArray;
+ static const int ALIGNMENT = 4; // must be power-of-2
+ int32_t ib;
+
+public:
+ SkipListLink() = default;
+ SkipListLink( const SkipListLink& rhs ) = default;
+ SkipListLink( nullptr_t unused ) { ib = 0; } // nullptr_t used to only allow nullptr or 0 as an argument,
+ // other ints or ptr types aren't convertible to nullptr_t
+ bool FNull() const { return ib == 0; }
+ void Nullify() { ib = 0; }
+ int ToInt() const { return ib; }
+
+ bool operator==( const SkipListLink& rhs ) const { return ( ib == rhs.ib ); }
+ bool operator!=( const SkipListLink& rhs ) const { return (ib != rhs.ib ); }
+ SkipListLink& operator=( const SkipListLink& rhs ) = default;
+
+ SkipListLink& Inc( int _ib )
+ {
+ Assert( FRounded( _ib ) );
+ ib += _ib;
+ return *this;
+ }
+
+ SkipListLink& Dec( int _ib )
+ {
+ Assert( FRounded( _ib ) );
+ ib -= _ib;
+ return *this;
+ }
+
+public:
+ static SkipListLink FromInt( int _ib )
+ {
+ Assert( FRounded( _ib ) );
+ SkipListLink link;
+ link.ib = _ib;
+ return link;
+ }
+
+ static_assert( FPowerOf2( ALIGNMENT ), "The following functions require ALIGNMENT to be a power-of-2" );
+
+ static SkipListLink Null() { return SkipListLink( 0 ); }
+ static int Roundup( int _ib ) { return ( _ib + ALIGNMENT - 1 ) & -ALIGNMENT; }
+ static bool FRounded( int _ib ) { return !( _ib & ( ALIGNMENT - 1 ) ); }
+};
+
+#include
+
+// SkipListLinkArray structure:
+// | Preamble | rgLinks[ cLinks ] |
+// Bytes: 0 1->x x->x+c*2
+// Preamable = A sequence of bytes with each 4-bits in it storing the lower order 4 bits of the link.
+// So each link is 16-bits in rgLinks[i] + 4-bits in preamble = 20-bits.
+// The 20-bits are further left-shifted to yield a 22-bit link (that can address 4-byte aligned upto 4mb).
+
+// Manipulates persisted representation of skiplist links of a given node.
+// The class layout doesn't define the persisted layout of the array.
+// Instead, its implementation defines the persisted layout.
+PERSISTED
+class SkipListLinkArray
+{
+public:
+ static const int REMOTE_BITS = 4; // bits per link stored in the preamble bytes
+ static const int LOCAL_BITS = 16; // bits stored with each link
+ static const int REMOTE_BITMASK = ( 1 << REMOTE_BITS ) - 1;
+ static const int LINK_MAX = ( 1 << ( LOCAL_BITS + REMOTE_BITS ) ) * SkipListLink::ALIGNMENT - 1; // 4mb
+
+private:
+ BYTE* m_rgb = nullptr;
+ int m_cLinks = 0;
+ int m_iOffset = 0;
+
+ SkipListLink GetLink_( int i ) const
+ {
+ Assert( i < m_cLinks );
+ const UnalignedLittleEndianPtr prgLinks = (USHORT*) &m_rgb[ CbPreamble( m_cLinks ) ];
+ int ilink = prgLinks[ i ] << REMOTE_BITS;
+ int remoteBits = m_rgb[ ( i * REMOTE_BITS ) / 8 ];
+ remoteBits = ( remoteBits >> ( ( i * REMOTE_BITS ) % 8 ) ) & REMOTE_BITMASK;
+ ilink |= remoteBits;
+ return SkipListLink::FromInt( ilink * SkipListLink::ALIGNMENT );
+ }
+
+ void SetLink_( int i, SkipListLink link )
+ {
+ UnalignedLittleEndianPtr prgLinks = (USHORT*) &m_rgb[ CbPreamble( m_cLinks ) ];
+
+ Assert( i < m_cLinks );
+ Assert( link.ib <= LINK_MAX );
+ int ilink = link.ib / SkipListLink::ALIGNMENT;
+ int remoteBits = ilink & REMOTE_BITMASK;
+ prgLinks[ i ] = (USHORT)( ilink >> REMOTE_BITS );
+ remoteBits <<= ( i * REMOTE_BITS ) % 8;
+ int remoteMask = ~( REMOTE_BITMASK << ( ( i * REMOTE_BITS ) % 8 ) );
+ m_rgb[ ( i * REMOTE_BITS ) / 8 ] &= remoteMask; // zero out old bits
+ m_rgb[ ( i * REMOTE_BITS ) / 8 ] |= remoteBits; // write new bits
+
+ Assert( GetLink_( i ) == link );
+ }
+
+public:
+ SkipListLinkArray() = default;
+ SkipListLinkArray( const SkipListLinkArray& ) = default;
+ SkipListLinkArray( BYTE* rgb, int cLinks, int iOffset )
+ : m_rgb( rgb ), m_cLinks( cLinks ), m_iOffset( iOffset ) {};
+
+ SkipListLinkArray& operator=( const SkipListLinkArray& ) = default;
+
+ SkipListLink operator[]( int i ) const { return GetLink_( m_iOffset + i ); }
+ void SetLink( int i, SkipListLink link ) { SetLink_( m_iOffset + i, link ); }
+ static constexpr int CbPreamble( int cLinks ) { return ( cLinks * REMOTE_BITS + 7 ) / 8; }
+ static constexpr int Cb( int cLinks ) { return CbPreamble( cLinks ) + cLinks * ( LOCAL_BITS / 8 ); }
+};
+
+#include
+
+PERSISTED
+struct SkipListNodeHdr
+{
+ static_assert( FHostIsLittleEndian(), "The union below needs to be fixed for big-endian architectures." );
+ union
+ {
+ struct
+ {
+ BYTE fDuplicate : 1; // indicates that the next node (at level 0) is a duplicate of this one.
+ BYTE reserved : 7; // reserved for future expansion
+ BYTE iLevel : 4; // skiplist level of the node
+ BBTBuffOpcode opcode : 4;
+ };
+ UnalignedLittleEndian le_usHeader;
+ };
+
+ SkipListNodeHdr() = default;
+ SkipListNodeHdr( const SkipListNodeHdr& rhs )
+ { le_usHeader = rhs.le_usHeader; }
+ bool IsValid() const { return ( reserved == 0 ); }
+
+ const SkipListNodeHdr& operator=( const SkipListNodeHdr& rhs )
+ {
+ le_usHeader = rhs.le_usHeader;
+ return *this;
+ }
+};
+
+PERSISTED
+class SkipListNode
+{
+ friend class SkipListAsserts;
+ friend class BBTBuff;
+ template friend class BBTBuffWriter;
+
+ static const USHORT CBKEY_MASK = 0x0fff;
+ static const USHORT CBKEY_FLAGS_SHIFT = 12;
+
+ static constexpr USHORT LShiftFlag( SkipListNodeFlags flags ) { return static_cast( flags ) << CBKEY_FLAGS_SHIFT; }
+
+ SkipListNodeHdr m_header;
+ UnalignedLittleEndian m_cbKey;
+ UnalignedLittleEndian m_cbData;
+ BYTE m_rgbNode[ 0 ]; // Variable sized strucures as shown above in the SkipListNode structure comment
+
+ SkipListNode( int level, BBTBuffOpcode opcode, int cbKey, int cbData )
+ {
+ Assert( level >= 0 && level < MAX_LEVELS );
+ Assert( cbKey <= CBKEY_MASK );
+ Assert( cbData <= USHRT_MAX );
+
+ m_header.le_usHeader = 0;
+ m_header.iLevel = level;
+ m_header.opcode = opcode;
+
+ m_cbKey = (USHORT) cbKey;
+ m_cbData = (USHORT) cbData;
+ memset( m_rgbNode, 0, CbLinks( level ) );
+ }
+
+ int IbLinks() const { return offsetof( SkipListNode, m_rgbNode ); }
+ int IbKey() const { return IbLinks() + CbLinks( m_header.iLevel ); }
+ int IbData() const { return IbKey() + CbKey(); }
+
+ BYTE* PbLinks() const { return ( ( (BYTE*) this ) + IbLinks() ); }
+ BYTE* PbKey() const { return ( ( (BYTE*) this ) + IbKey() ); }
+ BYTE* PbData() const { return ( ( (BYTE*) this ) + IbData() ); }
+
+ void SetDeleted( bool fDeleted ) { m_cbKey = ( fDeleted ? m_cbKey | LShiftFlag( fSLNDeleted ) : m_cbKey & ( ~LShiftFlag( fSLNDeleted ) ) ); }
+ void SetVersioned( bool fVersioned ) { m_cbKey = ( fVersioned ? m_cbKey | LShiftFlag( fSLNVersioned ) : m_cbKey & ( ~LShiftFlag( fSLNVersioned ) ) ); }
+ void SetCompressed( bool fCompressed ) { m_cbKey = ( fCompressed ? m_cbKey | LShiftFlag( fSLNCompressed ) : m_cbKey & ( ~LShiftFlag( fSLNCompressed ) ) ); }
+
+public:
+ // Node Basics
+
+ bool IsValid() const { return ( m_header.IsValid() && CbKey() > 0 && CbKey() <= cbKeyMostMost ); }
+ SkipListNodeHdr Header() const { return m_header; }
+
+
+ // Skiplist Navigation
+
+ int Level() const { return m_header.iLevel; }
+ SkipListLink LinkPrev0() const { return SkipListLinkArray{ PbLinks(), Level() + 2, 0 }[ 0 ]; }
+ SkipListLink LinkNext0() const { return SkipListLinkArray{ PbLinks(), Level() + 2, 0 }[ 1 ]; }
+ SkipListLinkArray RgLinksNext() const { return SkipListLinkArray{ PbLinks(), Level() + 2, 1 }; } // returns array of next links (LinkPrev0 isn't part of this array)
+ bool FDuplicateNext0() const { return m_header.fDuplicate; }
+ void SetLinkPrev0( SkipListLink link ) { SkipListLinkArray{ PbLinks(), Level() + 2, 0 }.SetLink( 0, link ); }
+ void SetDuplicateNext0( bool fDup ) { m_header.fDuplicate = fDup; }
+
+
+ // Node key/data/flags manipulation
+
+ BBTBuffOpcode Opcode() const { return m_header.opcode; }
+ int CbKey() const { return ( m_cbKey & CBKEY_MASK ); }
+ int CbData() const { return m_cbData; }
+ int Cb() const { return sizeof( SkipListNode ) + CbLinks( m_header.iLevel ) + CbKey() + CbData(); }
+ bool FDeleted() const { return !!( m_cbKey & LShiftFlag( fSLNDeleted ) ); }
+ bool FVersioned() const { return !!( m_cbKey & LShiftFlag( fSLNVersioned ) ); }
+ bool FCompressed() const { return !!( m_cbKey & LShiftFlag( fSLNCompressed ) ); }
+ SkipListNodeFlags FFlags() const { return static_cast( m_cbKey >> CBKEY_FLAGS_SHIFT ); }
+ KEY Key() const;
+ DATA Data() const;
+
+ void CopyKeyDataIntoBuffer( void* pvBuffer, int cbMost ) const;
+ void SetOpcode( BBTBuffOpcode opcode );
+ void SetNodeKey( const KEY& key );
+ void SetNodeData( const DATA& data );
+ void SetNodeFlags( SkipListNodeFlags flags );
+ int CmpKey( const KEY& keyRhs ) const;
+
+
+ // Creation/Sizing helpers
+
+ static constexpr int CbLinks( int level )
+ {
+ // Level 0 nodes contain 2 links: linkPrev0, linkNext0.
+ return SkipListLinkArray::Cb( level + 2 );
+ }
+
+ static constexpr int Cb( int level, int cbKey, int cbData )
+ {
+ return sizeof( SkipListNode ) + CbLinks( level ) + cbKey + cbData;
+ }
+
+ static SkipListNode* Create( void* pv, int level, BBTBuffOpcode opcode, int cbKey, int cbData )
+ {
+ return new ( pv ) SkipListNode( level, opcode, cbKey, cbData );
+ }
+};
+
+class SkipListAsserts
+{
+ static_assert( std::is_standard_layout::value, "SkipListLink should be a standard layout type." );
+ static_assert( std::is_standard_layout::value, "SkipListNodeHdr should be a standard layout type." );
+ static_assert( std::is_standard_layout::value, "SkipListNode should be a standard layout type." );
+ static_assert( sizeof( SkipListLink ) == 4, "SkipListLink must be 4 bytes." );
+ static_assert( SkipListNode::CBKEY_MASK >= cbKeyMostMost, "m_cbKey is too small for cbKeyMostMost." );
+ static_assert( offsetof( SkipListNode, m_cbKey ) == 2, "SkipListNode header must be 2 bytes." );
+ static_assert( SkipListNode::Cb( 0, 0, 0 ) == 11, "Minimum SkipListNode overhead must be 11 bytes." );
+};
+
+PERSISTED
+struct BBTBuffHeader
+{
+ BYTE nVersion; // bbtbuff format version
+ BYTE cMaxPages; // number of physical pages that make up the bbt buff
+ UnalignedLittleEndian le_ibMicFree; // offset where the next node is to be inserted
+ UnalignedLittleEndian le_cbFree; // total number of free bytes in the buff (can be different from ibMicFree because of deletes)
+ UnalignedLittleEndian le_cNodes; // total number of nodes in the bbt buff
+ BYTE rgbLinks[ SkipListLinkArray::Cb( MAX_LEVELS ) ]; // links to the first node in the bbt buff
+ BYTE reserved[ 2 ]; // align to 4-bytes
+};
+
+// Changing header size is a format breaking change!
+// Make sure to handle format compatibility requirements.
+static_assert( sizeof( BBTBuffHeader ) == 56, "BBTBuffHeader size changed." );
+
+INLINE SkipListLinkArray RgSkipListLinksHead( BBTBuffHeader* pHeader )
+{
+ return SkipListLinkArray{ pHeader->rgbLinks, MAX_LEVELS, 0 };
+}
+
+
+#include
+// END persisted structures
+///////////////////////////////////////////////////////////////////////////////
+
+struct PageOffsetTuple
+{
+ USHORT ipg;
+ USHORT ibOnPage;
+};
+
+struct BBTBuffChangeContext
+{
+ DBTIME dbtimeBefore;
+ DBTIME dbtimeCurr;
+ SkipListLink rgLinksPrev[ MAX_LEVELS ];
+ INT level;
+ SkipListLink linkCurr;
+};
+
+class BBTBuff
+{
+ // Companion classes for transacted writing.
+ template friend class BBTBuffWriter;
+ template friend class IBBTBuffTrxLog;
+ friend class BBTBuffRedo;
+ friend class DbTimeGuard;
+
+ // Debug extensions that need to inspect private state.
+ friend std::string DumpBBTBuff( const BBTBuff& bbtBuff, INT level, INT ib = 0 );
+ friend LOCAL ERR ErrEDBGDumpBBTBuff_( BBTBuff* pBBTBuffDebuggee, INT level );
+
+private:
+ BBTBuffHeader* m_pHeader = NULL;
+ CSR* m_pcsrBase = NULL; // Base page must stay latched for the lifetime of BBTBuff
+ CSR* m_rgcsrLatched = NULL;
+ SkipListNode* m_pnodeCurr = NULL;
+ INT m_ipgCurr = -1;
+ INT m_cbPageDataMax = 0;
+ BYTE m_cMaxPages = 0; // m_rgcsrLatched is sized based on this
+ LATCH m_latchType = latchNone;
+ BYTE m_ifmt = 0xff;
+
+ INT m_iLevelSeedTestOnly= -1; // only used in unit testing
+
+ // Needed for latching pages
+ PIB* m_ppib = NULL;
+ IFMP m_ifmp = ifmpNil;
+
+public:
+ BBTBuff() = default;
+ ~BBTBuff();
+
+ // Initialization
+
+ void Load( _In_ PIB* ppib, IFMP ifmp, _In_ CSR* pcsr, _In_ CSRHeapArray& rgcsrBBT, _In_ BBTBuffHeader* pbbtbHeader, LATCH latchType );
+ void Unload();
+ bool FLoaded() const;
+
+
+ // Page latch manipulation
+
+ ERR ErrLatchAll();
+ ERR ErrWriteLatchAll();
+ void Downgrade( LATCH latchType );
+ LATCH LatchType() const { return m_latchType; }
+
+
+ // BBT buffer navigation (seeks and moves)
+
+ enum SeekFlags : BYTE
+ {
+ sfSkipDuplicates = 0,
+ sfAllowDuplicates = 1
+ };
+
+ ERR ErrSeekLEQ( const KEY& key );
+ ERR ErrSeekGEQOldest( const KEY& key );
+ ERR ErrMoveFirst( SeekFlags fFlags );
+ ERR ErrMoveLast();
+ ERR ErrMoveNext( SeekFlags fFlags );
+ ERR ErrMovePrev( SeekFlags fFlags );
+ ERR ErrMoveToLatestInDuplicateSequence();
+
+ // Gets the ith previous duplicate node of the current (without moving the current).
+ // piDup (in/out): ith duplicate node to get. 0 = current node.
+ // Returns the index of the returned node in the duplicate chain
+ // e.g. can return a smaller piDup, if the BBTBuff didn't have enough duplicate versions.
+ ERR ErrGetDuplicate( _Out_ SkipListNode** ppnodeDup, _Inout_ int* piDup );
+
+
+ // Cursor manipulation
+
+ void ResetCurr();
+ SkipListNode* PnodeCurr() { return m_pnodeCurr; }
+ const SkipListNode* PnodeCurr() const { return m_pnodeCurr; }
+ SkipListLink GetLinkToCurrNode() const;
+ ERR ErrSetCurrNodeFromLink( SkipListLink link );
+
+
+ // Invariant Format
+
+ int CbMaxNodeSize() const { return m_cbPageDataMax; };
+ int Cpg() const { Assert( FLoaded() ); return m_cMaxPages; }
+ static int IBBTBuffFormatForPage( int cbPage );
+ static const BBTBuffFormat* PBBTBuffFormatForPage( int cbPage );
+ static int CbMax(); // returns the total size of the BBT buffer
+
+
+ // Buffer space
+
+ int CNodes() const { return m_pHeader->le_cNodes; }
+ int CbFree() const { return m_pHeader->le_cbFree; }
+ int IbFree() const { return m_pHeader->le_ibMicFree->ToInt(); }
+
+
+ // Misc
+
+ bool FCanInsert( const KEY& key, const DATA& data, _Out_ int* pcbReq );
+ SkipListNode* PnodeFromLink( SkipListLink link ) const;
+
+
+ // These operations do unlogged modifications to the BBTBuff.
+ // They must be logged externally.
+
+ template
+ void MergeAndDelNodes(
+ TMergeIt itNodesMergeBegin,
+ const TMergeIt itNodesMergeEnd,
+ TDelIt itNodesDelBegin,
+ const TDelIt itNodesDelEnd,
+ SkipListLink linkIbMergeStart,
+ _Out_ int* pcNodesMerged,
+ _Out_ int* pcNodesDel );
+
+
+ // Validation
+
+ bool FIsHeaderValid() const;
+ ERR ErrAssertIsLatestInDuplicateSequence( const SkipListNode* pnode );
+ ERR ErrAssertIsOldestInDuplicateSequence( const SkipListNode* pnode );
+ ERR ErrValidate();
+
+
+ // BBTBuff page initialization functions
+
+public:
+ static void InitBBTBuffRoot( FUCB* pfucb, CSR* pcsr );
+ static void InitBBTBuffNonRoot( CSR* pcsr );
+ static void GetBBTBuffRoot( const CSR& csr, LINE* pline );
+ static BBTBuffHeader* PBBTHeader( const LINE& line );
+private:
+ static void InitBBTBuffHeader( _Out_ BBTBuffHeader* pbbtbHeader, _In_ int cMaxPages );
+
+
+private:
+ // Format primitives
+
+ const BBTBuffFormat* PFormat() const;
+ BYTE* PbPage( int ipg ) const { return (BYTE*) Pcsr( ipg )->Cpage().PvBuffer(); }
+ int IbHeader() const;
+ int IbPageDataBegin( int ipg ) const { return ( ipg > 0 ? m_pcsrBase->Cpage().CbPageHeader() : IbHeader() + sizeof( BBTBuffHeader ) ); }
+ int IbPageDataEnd( int ipg ) const { return ( ipg > 0 ? g_cbPage - CPAGE::CbTagReservedLegacy() : IbHeader() + PFormat()->cbBBTRoot ); }
+
+
+ // Latch manipulation
+
+ CSR* Pcsr( int ipg ) const { return ( ipg > 0 ? &m_rgcsrLatched[ ipg - 1 ] : m_pcsrBase ); }
+ ERR ErrEnsurePageLatched( SkipListLink link, LATCH latchType );
+ ERR ErrEnsurePageLatched( int ipgOffset, LATCH latchType );
+ void DowngradeLatches();
+ void AssertLatchedAll( LATCH latchType );
+ void AssertReadyForWrite();
+
+
+ // SkiplinstLink Translation
+
+ PageOffsetTuple IpgOffsetFromLink( SkipListLink link ) const;
+ SkipListLink LinkFromIpgOffset( int ipg, int ibOnPage ) const;
+ SkipListNode* PnodeFromIpgOffset( PageOffsetTuple pgOffset ) const;
+ ERR ErrPnodeFromLink_AcqLatch( SkipListLink link, SkipListNode** ppnode );
+
+
+ // Misc
+
+ void ChangeCurr( int ipg, SkipListNode* pnodeCurr );
+ ERR ErrGetLatestInDuplicateSequence( SkipListNode* pnodeCurr, _Out_ SkipListLink* plinkLatestDup );
+ static int GenLevel( int iSeed );
+ int GenLevel();
+
+
+ // Internal implementation of certain operations
+
+#ifdef ENABLE_JET_UNIT_TEST
+ // ErrSeek_() needs unit testing directly
+public:
+#endif
+ enum class SeekMode { LT, LEQ };
+ enum class SeekPos { Prev, Curr };
+ ERR ErrSeek_(
+ const KEY& key,
+ SeekMode seekMode,
+ SeekPos seekPos,
+ _Out_ int* piResult,
+ _Out_ SkipListLink rgLinks[ MAX_LEVELS ],
+ _Out_ SkipListNode* rgNodes[ MAX_LEVELS ] );
+
+private:
+ SkipListNode* PnodeInsert_(
+ const BBTBuffChangeContext& changeCtx,
+ SkipListNode* rgNodes[ MAX_LEVELS ],
+ BBTBuffOpcode opcode,
+ const KEY& key,
+ const DATA& data,
+ SkipListNodeFlags flags,
+ bool fDuplicate );
+
+ void Delete_(
+ BBTBuffChangeContext changeCtx,
+ SkipListNode* rgNodes[ MAX_LEVELS ],
+ const SkipListNode* pnodeToDelete );
+
+ void RangeDelete_( SkipListLink linkFirst, int cNodes );
+
+ template
+ void CopyMergeAndDelNodes_(
+ BYTE** rgpbPage,
+ TMergeIt itNodesMergeBegin,
+ const TMergeIt itNodesMergeEnd,
+ TDelIt itNodesDelBegin,
+ const TDelIt itNodesDelEnd,
+ SkipListLink linkIbMergeStart,
+ _Out_ int* pcNodesMerged,
+ _Out_ int* pcNodesDel );
+
+ // Unit test hooks
+#ifdef ENABLE_JET_UNIT_TEST
+public:
+ void SetLevelSeed( int iSeed ) { m_iLevelSeedTestOnly = iSeed; }
+#endif
+};
+
+enum CursorLocation : BYTE
+{
+ clocInvalid = 0,
+ clocFailed,
+ clocOnTarget,
+ clocOnTargetOlderVersion, // on an older version of the target node
+ clocBeforeTarget,
+ clocAfterTarget,
+ clocBeforeFirst, // before first node on the page (not on the tree)
+ clocAfterLast, // after last node on the page (not on the tree)
+};
+
+INLINE bool FCLocOnNode( CursorLocation cloc )
+{
+ return ( cloc == clocOnTarget || cloc == clocBeforeTarget || cloc == clocAfterTarget );
+}
+
+INLINE bool FCLocValid( CursorLocation cloc )
+{
+ return ( cloc != clocInvalid && cloc != clocFailed );
+}
+
+// BBTBuff Currency Stack Register and associated state.
+struct BBTBuffCSR
+{
+ CSR csr;
+ CSRHeapArray rgcsrBBT;
+ BBTBuff bbtbuff;
+ SkipListLink link;
+ CursorLocation cursorLoc;
+
+ BBTBuffCSR() : cursorLoc( clocInvalid )
+ {
+ link.Nullify();
+ }
+
+ // Release all latches except base page latch.
+ // Caller is responsible for managing base page latch.
+ void Release( bool fTossImmediate = false )
+ {
+ // Releasing latches, bbtbuff is invalid.
+ // But currency is still valid, i.e. link and cursorLoc are still valid.
+ bbtbuff.Unload();
+
+ if ( rgcsrBBT != NULL )
+ {
+ for ( int i = 0; i < rgcsrBBT.CItems(); i++ )
+ {
+ // All operations on BBTBuff pages must be kept at the same dbtime.
+ Assert( !rgcsrBBT[ i ].FLatched() || csr.Dbtime() == rgcsrBBT[ i ].Dbtime() );
+ rgcsrBBT[ i ].ReleasePage( fTossImmediate );
+ }
+ }
+
+ csr.ReleasePage( fTossImmediate );
+ }
+
+ void Reset()
+ {
+ Assert( !bbtbuff.FLoaded() );
+ cursorLoc = clocInvalid;
+ link.Nullify();
+ rgcsrBBT.ForEach( []( CSR& csr ) { csr.Reset(); } );
+ csr.Reset();
+ }
+
+ bool FValid()
+ {
+ // UA_TODO: fix validity criteria
+ return true;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SkipListNode INLINE methods
+
+INLINE KEY SkipListNode::Key() const
+{
+ Assert( IsValid() );
+ KEY key;
+ key.prefix.Nullify();
+ key.suffix.SetPv( PbKey() );
+ key.suffix.SetCb( CbKey() );
+ return key;
+}
+
+INLINE DATA SkipListNode::Data() const
+{
+ Assert( IsValid() );
+ DATA data;
+ data.SetPv( PbData() );
+ data.SetCb( CbData() );
+ return data;
+}
+
+INLINE void SkipListNode::CopyKeyDataIntoBuffer( void* pvBuffer, int cbMost ) const
+{
+ Assert( PbData() == PbKey() + CbKey() ); // data must immediately follow the key
+ INT cbCopy = min( cbMost, CbKey() + CbData() );
+ UtilMemCpy( pvBuffer, PbKey(), cbCopy );
+}
+
+INLINE void SkipListNode::SetOpcode( BBTBuffOpcode opcode )
+{
+ m_header.opcode = opcode;
+}
+
+INLINE void SkipListNode::SetNodeKey( const KEY& key )
+{
+ Assert( key.Cb() == CbKey() );
+ key.CopyIntoBuffer( PbKey(), CbKey() );
+}
+
+INLINE void SkipListNode::SetNodeData( const DATA& data )
+{
+ Assert( data.Cb() == CbData() );
+ UtilMemCpy( PbData(), data.Pv(), CbData() );
+}
+
+INLINE void SkipListNode::SetNodeFlags( SkipListNodeFlags flags )
+{
+ USHORT usFlags = static_cast( flags ) << CBKEY_FLAGS_SHIFT;
+ Assert( 0 == ( usFlags & CBKEY_MASK ) );
+ m_cbKey |= usFlags;
+}
+
+INLINE int SkipListNode::CmpKey( const KEY& keyRhs ) const
+{
+ KEY keyLhs;
+ keyLhs.prefix.Nullify();
+ keyLhs.suffix.SetPv( PbKey() );
+ keyLhs.suffix.SetCb( CbKey() );
+ return ::CmpKey( keyLhs, keyRhs );
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// BBTBuff INLINE methods
+
+INLINE const BBTBuffFormat* BBTBuff::PFormat() const
+{
+ Assert( m_ifmt < _countof( BBTBUFF_FORMAT_CONSTANTS ) );
+ return &BBTBUFF_FORMAT_CONSTANTS[ m_ifmt ];
+}
+
+INLINE int BBTBuff::IbHeader() const
+{
+ auto ib = ( (BYTE*) m_pHeader ) - PbPage( 0 );
+ Assert( ib < g_cbPage );
+ return (int) ib;
+}
+
+INLINE PageOffsetTuple BBTBuff::IpgOffsetFromLink( SkipListLink link ) const
+{
+ Assert( !link.FNull() );
+ PageOffsetTuple tuple;
+ int ib = link.ToInt();
+ ib -= PFormat()->cbBBTRoot;
+ if ( ib >= 0 )
+ {
+ tuple.ipg = (USHORT) ( 1 + ib / m_cbPageDataMax );
+ tuple.ibOnPage = (USHORT) ( m_pcsrBase->Cpage().CbPageHeader() + ( ib % m_cbPageDataMax ) ); // SkipListLink::ib = 0 points to BBTBuffHeader
+ }
+ else
+ {
+ tuple.ipg = 0;
+ tuple.ibOnPage = (USHORT) ( link.ToInt() + IbHeader() );
+ }
+
+ Assert( tuple.ibOnPage != 0 );
+ return tuple;
+}
+
+INLINE SkipListLink BBTBuff::LinkFromIpgOffset( int ipg, int ibOnPage ) const
+{
+ Assert( ipg < Cpg() );
+ Assert( ibOnPage != 0 );
+
+ int ib;
+ if ( ipg > 0 )
+ {
+ ib = PFormat()->cbBBTRoot;
+ ib += ( ipg - 1 ) * m_cbPageDataMax;
+ ib += ( ibOnPage - m_pcsrBase->Cpage().CbPageHeader() ); // SkipListLink::ib = 0 points to BTBuffHeader
+ }
+ else
+ {
+ ib = ibOnPage - IbHeader();
+ }
+
+ Assert( !( ib & 0x03 ) );
+ return SkipListLink::FromInt( ib );
+}
+
+INLINE SkipListNode* BBTBuff::PnodeFromIpgOffset( PageOffsetTuple pgOffset ) const
+{
+ Assert( Pcsr( pgOffset.ipg )->FLatched() );
+ auto pnode = (SkipListNode*) ( PbPage( pgOffset.ipg ) + pgOffset.ibOnPage );
+ Assert( pnode->IsValid() );
+ return pnode;
+}
+
+INLINE SkipListNode* BBTBuff::PnodeFromLink( SkipListLink link ) const
+{
+ if ( link.FNull() )
+ {
+ return NULL;
+ }
+
+ auto pgOffset = IpgOffsetFromLink( link );
+ Assert( Pcsr( pgOffset.ipg )->FLatched() );
+ return PnodeFromIpgOffset( pgOffset );
+}
+
+INLINE ERR BBTBuff::ErrPnodeFromLink_AcqLatch( SkipListLink link, SkipListNode** ppnode )
+{
+ ERR err = JET_errSuccess;
+
+ if ( link.FNull() )
+ {
+ *ppnode = NULL;
+ return err;
+ }
+
+ auto pgOffset = IpgOffsetFromLink( link );
+ if ( !Pcsr( pgOffset.ipg )->FLatched() )
+ {
+ CallR( ErrEnsurePageLatched( pgOffset.ipg, m_latchType ) );
+ }
+
+ *ppnode = PnodeFromIpgOffset( pgOffset );
+ return err;
+}
+
+INLINE SkipListLink BBTBuff::GetLinkToCurrNode() const
+{
+ if ( m_pnodeCurr == NULL )
+ {
+ return SkipListLink::Null();
+ }
+
+ BYTE* pbPage = PbPage( m_ipgCurr );
+ Assert( m_pnodeCurr->IsValid() );
+ Assert( m_ipgCurr >= 0 );
+ Assert( Pcsr( m_ipgCurr )->FLatched() && pbPage != NULL );
+
+ BYTE* pb = (BYTE*) m_pnodeCurr;
+ EnforceSz( pb >= pbPage, "BBTBuff corruption !" );
+ EnforceSz( pb < ( pbPage + g_cbPage ), "BBTBuff corruption !" );
+ EnforceSz( pb + m_pnodeCurr->Cb() < ( pbPage + g_cbPage ), "BBTBuff corruption !" );
+
+ auto ibOnPage = pb - pbPage;
+ Assert( ibOnPage + m_pnodeCurr->Cb() <= IbPageDataEnd( m_ipgCurr ) );
+ SkipListLink link = LinkFromIpgOffset( m_ipgCurr, (int) ibOnPage );
+ Assert( link.ToInt() < m_pHeader->le_ibMicFree->ToInt() );
+ return link;
+}
+
+INLINE void BBTBuff::ResetCurr()
+{
+ Assert( ( m_ipgCurr < 0 ) == ( m_pnodeCurr == NULL ) );
+ m_ipgCurr = -1;
+ m_pnodeCurr = NULL;
+}
+
+INLINE void BBTBuff::ChangeCurr( int ipg, SkipListNode* pnodeCurr )
+{
+ Assert( ipg >= 0 && ipg < Cpg() );
+ Assert( Pcsr( ipg )->FLatched() );
+
+ BYTE* pb = (BYTE*) pnodeCurr;
+ BYTE* pbPage = PbPage( ipg );
+ Assert( pb >= pbPage );
+ Assert( pb < ( pbPage + g_cbPage ) );
+ Assert( pb + pnodeCurr->Cb() < ( pbPage + g_cbPage ) );
+
+ m_ipgCurr = ipg;
+ m_pnodeCurr = pnodeCurr;
+}
+
+INLINE int BBTBuff::GenLevel( int iSeed )
+{
+ int level = 0;
+ const int SEED_MAX = 1 << ( MAX_LEVELS - 1 );// a max value of 0x7fff will generate a level of 15
+ for ( int r = iSeed % SEED_MAX; ( r & 1 ); r >>= 1 )
+ {
+ level++;
+ }
+
+ return level;
+}
+
+INLINE int BBTBuff::GenLevel()
+{
+#ifdef ENABLE_JET_UNIT_TEST
+ return GenLevel( m_iLevelSeedTestOnly >= 0 ? m_iLevelSeedTestOnly : rand() );
+#else
+ return GenLevel( rand() );
+#endif
+}
+
+INLINE int BBTBuff::IBBTBuffFormatForPage( int cbPage )
+{
+ Assert( FPowerOf2( cbPage ) );
+ unsigned long ulFmt = Log2OfPowerOf2( (unsigned long) cbPage ) - 12; // 2^12 = 4k, first entry in the format constants table
+ const BBTBuffFormat* pFormat = &BBTBUFF_FORMAT_CONSTANTS[ ulFmt ];
+ Assert( pFormat->cbCPAGE == cbPage );
+ return (int) ulFmt;
+}
+
+INLINE const BBTBuffFormat* BBTBuff::PBBTBuffFormatForPage( int cbPage )
+{
+ return &BBTBUFF_FORMAT_CONSTANTS[ IBBTBuffFormatForPage( cbPage ) ];
+}
+
+INLINE int BBTBuff::CbMax()
+{
+ // BBTBuff doesn't insert tags/ilines. It uses the page data space as one big buffer.
+ // But to keep CPAGE checks happy, we can't reclaim the reserved tag.
+ const BBTBuffFormat* pFormat = PBBTBuffFormatForPage( g_cbPage );
+ return pFormat->cbBBTRoot + ( pFormat->cpgInBBTBuff - 1 ) * ( CPAGE::CbPageDataMaxNoInsert( g_cbPage ) );
+}
+
+// Performs an evict operation, deleting required local nodes, while merging external nodes.
+// This operation must be externally logged.
+template
+void BBTBuff::MergeAndDelNodes(
+ TMergeIt itNodesMergeBegin,
+ const TMergeIt itNodesMergeEnd,
+ TDelIt itNodesDelBegin,
+ const TDelIt itNodesDelEnd,
+ SkipListLink linkIbMergeStart,
+ _Out_ int* pcNodesMerged,
+ _Out_ int* pcNodesDel )
+{
+ AssertReadyForWrite(); // must already be dirtied
+
+ BYTE** rgpbPage = (BYTE**) _alloca( sizeof( BYTE* ) * Cpg() );
+ Assert( rgpbPage );
+
+ for ( int i = 0; i < Cpg(); i++ )
+ {
+ BFAlloc( bfasTemporary, (void**) &rgpbPage[ i ], m_pcsrBase->Cpage().CbPage() ); // can't fail
+ Assert( rgpbPage[ i ] );
+ }
+
+ CopyMergeAndDelNodes_(
+ rgpbPage,
+ itNodesMergeBegin,
+ itNodesMergeEnd,
+ itNodesDelBegin,
+ itNodesDelEnd,
+ linkIbMergeStart,
+ pcNodesMerged,
+ pcNodesDel );
+
+ // Copy root page (BBTBuffHeader + any data)
+ memcpy(
+ PbPage( 0 ) + IbHeader(),
+ rgpbPage[ 0 ] + IbHeader(),
+ PFormat()->cbRoot );
+
+ // if the last node fits perfectly at the end of the last page, ibMicFree can point to the next page
+ int ipgLast = min( Cpg() - 1, IpgOffsetFromLink( m_pHeader->le_ibMicFree ).ipg );
+ for ( int i = 1; i <= ipgLast; i++ )
+ {
+ // Copy back the page at the appropriate offset
+ int cbCopy = IbPageDataEnd( i ) - IbPageDataBegin( i );
+ memcpy(
+ PbPage( i ) + IbPageDataBegin( i ),
+ rgpbPage[ i ] + IbPageDataBegin( i ),
+ cbCopy );
+ }
+
+ // UA_TODO: pattern-fill leftover space in pages
+
+ // Cleanup allocated memory
+ for ( int i = 0; i < Cpg(); i++ )
+ {
+ BFFree( rgpbPage[ i ] );
+ }
+}
+
+// Makes a copy of the current BBTBuff while deleting specified nodes and merging in as many nodes as can fit in.
+// Inputs:
+// 1. An array of BYTE* pointers pointing to allocated memory for each page in the BBTBuff.
+// 2. A LegacyForwadrIterator specifying merged nodes. The iterator should return pointers to objects that can pass for a SkipListNode.
+// 3. A LegacyForwardIterator specifying deleted nodes. The iterator should return on-page addresses of nodes that should be deleted.
+// 4. Offset in BBTBuff where the merged nodes are placed.
+//
+// Outputs:
+// 1. Count of nodes merged (can be less than the input).
+// 2. Count of nodes deleted.
+template
+void BBTBuff::CopyMergeAndDelNodes_(
+ BYTE** rgpbPage,
+ TMergeIt itNodesMergeBegin,
+ const TMergeIt itNodesMergeEnd,
+ TDelIt itNodesDelBegin,
+ const TDelIt itNodesDelEnd,
+ SkipListLink linkIbMergeStart,
+ _Out_ int* pcNodesMerged,
+ _Out_ int* pcNodesDel )
+{
+ using TMergeNode = std::iterator_traits::value_type;
+ using TDelItValue = std::iterator_traits::value_type;
+ enum NodeSource { nsInvalid = 0, nsLocal, nsMerge };
+ static_assert( std::is_same::value == true, "TDelIt must return SkipListLink" );
+
+ // The new pages being constructed have to be mem-copyable into the actual cpage. So we need
+ // to obey the current strucutre of the pages comprising the BBTBuff.
+ // This means that we need to construct the skip list to make sure that it begins at offsets
+ // dictated by the current root (for the root page). For the other pages, it needs to obey
+ // the current structure of the page, which for now is just leaving space for the page header.
+
+ // Non-standard, should use std::distance() but requires RandomAccessIterator,
+ // that we don't want to support.
+ auto cNodesToMerge = itNodesMergeEnd - itNodesMergeBegin;
+ Assert( cNodesToMerge <= INT32_MAX );
+
+ const SkipListLinkArray rgLinksHead = RgSkipListLinksHead( m_pHeader );
+ SkipListNode* rgpNodePrevAtLevel[ MAX_LEVELS ] = { 0 };
+ TMergeNode pnodeMerge = ( itNodesMergeBegin != itNodesMergeEnd ? *itNodesMergeBegin : nullptr );
+ SkipListLink linkDel = ( itNodesDelBegin != itNodesDelEnd ? *itNodesDelBegin : SkipListLink::Null() );
+ SkipListLink linkLocal = rgLinksHead[ 0 ];
+ SkipListNode* pnodeLocal = PnodeFromLink( linkLocal );
+ SkipListNode* pnodePrevNew = NULL;
+ int cNodes = 0;
+ int iNodesMerge = 0;
+ int iNodesDel = 0;
+ int cbFree = CbMax() - sizeof( BBTBuffHeader );
+ SkipListLink ibCurrLocal = SkipListLink::FromInt( sizeof( BBTBuffHeader ) ); // leave space for the header
+ SkipListLink ibCurrMerge = linkIbMergeStart;
+ SkipListLink linkPrev0( 0 );
+ BBTBuffHeader* pHeader = (BBTBuffHeader*) ( rgpbPage[ 0 ] + IbHeader() );
+ SkipListLinkArray rgLinksHeadNew = RgSkipListLinksHead( pHeader );
+
+ while( pnodeLocal != NULL || pnodeMerge != NULL )
+ {
+ NodeSource nodeSrcCurr = nsInvalid;
+ SkipListLink* pibCurr = NULL;
+ if ( pnodeLocal != NULL && pnodeMerge != NULL )
+ {
+ int result = pnodeLocal->CmpKey( pnodeMerge->Key() );
+ if ( result <= 0 )
+ {
+ nodeSrcCurr = nsLocal;
+ pibCurr = &ibCurrLocal;
+ }
+ else
+ {
+ // Evicted nodes from ancestors are more recent, must be inserted later than equal local nodes.
+ nodeSrcCurr = nsMerge;
+ pibCurr = &ibCurrMerge;
+ }
+ }
+ else if ( pnodeLocal != NULL )
+ {
+ nodeSrcCurr = nsLocal;
+ pibCurr = &ibCurrLocal;
+ }
+ else
+ {
+ Assert( pnodeMerge != NULL );
+ nodeSrcCurr = nsMerge;
+ pibCurr = &ibCurrMerge;
+ }
+
+ // Skip if the current node matches a node in delete sequence
+ if ( nodeSrcCurr == nsMerge || linkLocal != linkDel )
+ {
+ // Compute space needed for the current node
+ //
+
+ // Re-level deterministically, we can because we are appending sequentially.
+ // Remove the effect of merged nodes on local node levels. This is required to generate local nodes
+ // with the same size as we calculated earlier and reserved ( ErrReorg_CalcIbMerge() ).
+ // Not doing so can result in overrunning our estimate, causing local nodes not to fit.
+ // UA_TODO: The skip list will not be optimally laid out. But I don't think it is a problem.
+ int level = GenLevel( nodeSrcCurr == nsLocal ? cNodes - iNodesMerge : cNodes );
+ BBTBuffOpcode opcodeCurr = ( nodeSrcCurr == nsLocal ? pnodeLocal->Opcode() : pnodeMerge->Opcode() );
+ KEY keyCurr = ( nodeSrcCurr == nsLocal ? pnodeLocal->Key() : pnodeMerge->Key() );
+ DATA dataCurr = ( nodeSrcCurr == nsLocal ? pnodeLocal->Data() : pnodeMerge->Data() );
+ int cbUsed = SkipListLink::Roundup( SkipListNode::Cb( level, keyCurr.Cb(), dataCurr.Cb() ) ); // count wasted space too
+
+ if ( cbUsed > CbMaxNodeSize() )
+ {
+ // Generate level 0 node to eliminate overhead as much as we can.
+ level = 0;
+ cbUsed = SkipListLink::Roundup( SkipListNode::Cb( level, keyCurr.Cb(), dataCurr.Cb() ) );
+ EnforceSz( cbUsed <= CbMaxNodeSize(), "BBTBuff MergeNodeTooBig" ); // how was this node able to fit earlier?
+ }
+
+ SkipListLink ibPrev = *pibCurr; // needed to calcualte wasted space at the end of a page
+ PageOffsetTuple pgOffsetCurr = IpgOffsetFromLink( *pibCurr );
+ const int cbLeft = ( pgOffsetCurr.ipg < Cpg() ? IbPageDataEnd( pgOffsetCurr.ipg ) - pgOffsetCurr.ibOnPage : 0 );
+ if ( cbUsed > cbLeft )
+ {
+ // Move to new page if current page is full
+ pgOffsetCurr.ipg++;
+ if ( pgOffsetCurr.ipg >= Cpg() )
+ {
+ if ( nodeSrcCurr == nsMerge )
+ {
+ // Ran out of space, can't merge external nodes anymore.
+ // But we still have to merge all the local nodes.
+ // This will leave pseqNodesMerge positioned on the last node to fail merge,
+ // and then will proceed to merge in all local nodes.
+ pnodeMerge = NULL;
+ continue; // will try merging current pnodeLocal next
+ }
+ else
+ {
+ // This should never hit. We reserve the space needed to copy over local nodes,
+ // and only merge in as many external nodes as can fit.
+ EnforceSz( false, "BBTBuff MergeEvictedOverflow" );
+ }
+ }
+
+ Assert( rgpbPage[ pgOffsetCurr.ipg ] != NULL );
+ pgOffsetCurr.ibOnPage = (USHORT) IbPageDataBegin( pgOffsetCurr.ipg );
+ *pibCurr = LinkFromIpgOffset( pgOffsetCurr.ipg, pgOffsetCurr.ibOnPage );
+ }
+
+ // Alloc and copy to new node
+ SkipListLink ibNew = *pibCurr;
+ pibCurr->Inc( cbUsed );
+ cbFree -= ( pibCurr->ToInt() - ibPrev.ToInt() ); // count wasted space because of a page switch, too
+
+ EnforceSz( ibCurrLocal.ToInt() <= linkIbMergeStart.ToInt(), "BBTBuff ReorgLocalNodeOverflow" );
+
+ SkipListNode* pnodeNew = SkipListNode::Create( rgpbPage[ pgOffsetCurr.ipg ] + pgOffsetCurr.ibOnPage, level, opcodeCurr, keyCurr.Cb(), dataCurr.Cb() );
+ pnodeNew->SetNodeKey( keyCurr );
+ pnodeNew->SetNodeData( dataCurr );
+ pnodeNew->SetNodeFlags( nodeSrcCurr == nsLocal ? pnodeLocal->FFlags() : pnodeMerge->FFlags() );
+
+ // Recompute duplicate flag
+ Assert( linkPrev0.FNull() == ( pnodePrevNew == NULL ) );
+ if ( pnodePrevNew != NULL )
+ {
+ // Since we are only adding nodes, technically we can only recompute when FDuplicate() is false.
+ // But this can be broken if a caller combines duplicate nodes into 1, invalidating duplicate flags of the merge sequence.
+ // So always recompute.
+ Assert( !pnodePrevNew->FDuplicateNext0() );
+ if ( pnodePrevNew->CmpKey( pnodeNew->Key() ) == 0 )
+ {
+ pnodePrevNew->SetDuplicateNext0( true );
+ }
+ }
+
+ // Adjust links
+ pnodeNew->SetLinkPrev0( linkPrev0 );
+ SkipListLinkArray rgLinksNew = pnodeNew->RgLinksNext();
+ for ( int i = 0; i <= level; i++ )
+ {
+ ( rgpNodePrevAtLevel[ i ] != NULL ? rgpNodePrevAtLevel[ i ]->RgLinksNext() : rgLinksHeadNew )
+ .SetLink( i, ibNew );
+ rgpNodePrevAtLevel[ i ] = pnodeNew;
+ }
+
+ linkPrev0 = ibNew;
+ pnodePrevNew = pnodeNew;
+ cNodes++;
+ }
+ else
+ {
+ // Node should be deleted.
+ // Deleted node was identified by a link comparison. This works because nodes can't move around during evict-merge.
+ // Local links/pointers only become invalid after the merge copies back data to BBTBuff.
+ Assert( nodeSrcCurr == nsLocal ); // Only local nodes allowed in del sequence.
+ ++iNodesDel;
+ ++itNodesDelBegin;
+ linkDel = ( itNodesDelBegin != itNodesDelEnd ? *itNodesDelBegin : SkipListLink::Null() );
+ }
+
+ // MoveNext
+ if ( nodeSrcCurr == nsLocal )
+ {
+ linkLocal = pnodeLocal->LinkNext0();
+ pnodeLocal = PnodeFromLink( pnodeLocal->LinkNext0() );
+ }
+ else
+ {
+ Assert( nodeSrcCurr == nsMerge );
+ ++iNodesMerge;
+ ++itNodesMergeBegin;
+ pnodeMerge = ( itNodesMergeBegin != itNodesMergeEnd ? *itNodesMergeBegin : nullptr );
+ }
+ }
+
+ Assert( linkDel.FNull() ); // all deleted nodes should've been matched
+ EnforceSz( cNodes == m_pHeader->le_cNodes + iNodesMerge - iNodesDel, "BBTBuffReorg MissingNodes" );
+ EnforceSz( ibCurrMerge.ToInt() == CbMax() - cbFree, "BBTBuffReorg BadSpace" );
+
+ // Null-terminate all levels of the new skip list.
+ SkipListLink linkNull( 0 );
+ for ( int i = 0; i < MAX_LEVELS; i++ )
+ {
+ ( rgpNodePrevAtLevel[ i ] != NULL ? rgpNodePrevAtLevel[ i ]->RgLinksNext() : rgLinksHeadNew )
+ .SetLink( i, linkNull );
+ }
+
+ // Fix the new header
+ pHeader->nVersion = m_pHeader->nVersion;
+ pHeader->cMaxPages = m_pHeader->cMaxPages;
+ pHeader->le_cNodes = cNodes;
+ pHeader->le_cbFree = cbFree;
+ pHeader->le_ibMicFree = ibCurrMerge;
+
+ Assert( !rgLinksHeadNew[ 0 ].FNull() || cNodes == 0 );
+
+ // pHeader->rgSkipListLinksHead has already been fixed up
+ // We are done. New re-organized pages are in rgpbPage.
+ if ( pcNodesMerged != NULL )
+ {
+ *pcNodesMerged = iNodesMerge;
+ }
+ if ( pcNodesDel != NULL )
+ {
+ *pcNodesDel = iNodesDel;
+ }
+}
diff --git a/dev/ese/src/inc/bbtbuffwriter.hxx b/dev/ese/src/inc/bbtbuffwriter.hxx
new file mode 100644
index 00000000..27345bba
--- /dev/null
+++ b/dev/ese/src/inc/bbtbuffwriter.hxx
@@ -0,0 +1,775 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "bbtbuff.hxx"
+
+/************************************************************************************************************
+Provides a wrapper that allows transacted write operations on a BBTBuff.
+IBBTBuffTrxLog defines the interface that can be implemented to capture the operations in a trx log.
+The implementation of IBBTBuffTrxLog is responsible for correctly recording the details of the operation,
+and ensuring durability/redo guarantees.
+
+BBTBuffWriter only guarantees that each write operation is atomic, and in case of a failure,
+there will be no side-effects and the operation will be cleanly undone.
+
+Certain trx log concepts from the engine above have leaked into the BBTBuffWriter.
+Following are managed here for the BBT buffer.
+1. DBTIMEs and page dirtying.
+************************************************************************************************************/
+
+// Interface class for a transaction logger needed for write operations on a BBTBuff.
+// Uses CRTP to do static polymorphism.
+template
+class IBBTBuffTrxLog
+{
+public:
+ BBTBuff* const m_pbbtbuff;
+ DBTIME m_dbtimeCoordinated = dbtimeNil;
+
+ IBBTBuffTrxLog( BBTBuff * pbbtbuff ) : m_pbbtbuff( pbbtbuff )
+ {}
+
+ ERR ErrLogInsert(
+ const BBTBuffChangeContext& changeCtx,
+ BBTBuffOpcode opcode,
+ const KEY& key,
+ const DATA& data,
+ SkipListNodeFlags flags )
+ {
+ return static_cast( this )->ErrLogInsert( changeCtx, opcode, key, data, flags );
+ }
+
+ ERR ErrLogDelete(
+ const BBTBuffChangeContext& changeCtx,
+ const SkipListNode* pnodeDel )
+ {
+ return static_cast( this )->ErrLogDelete( changeCtx, pnodeDel );
+ }
+
+ ERR ErrLogRangeDelete(
+ DBTIME dbtimeBefore,
+ DBTIME dbtimeCurr,
+ SkipListLink linkFirst,
+ int cNodes )
+ {
+ return static_cast( this )->ErrLogRangeDelete( dbtimeBefore, dbtimeCurr, linkFirst, cNodes );
+ }
+
+ ERR ErrLogMergeAndDel(
+ DBTIME dbtimeBefore,
+ DBTIME dbtimeCurr,
+ _In_count_( cNodesMerged ) const SkipListNode** rgNodesMerged,
+ _In_count_( cNodesDel ) SkipListLink* rgLinksDel,
+ int cNodesMerged,
+ int cNodesDel,
+ SkipListLink linkIbMergeStart )
+ {
+ return static_cast( this )->ErrLogMergeAndDel( dbtimeBefore, dbtimeCurr, rgNodesMerged, rgLinksDel, cNodesMerged, cNodesDel, linkIbMergeStart );
+ }
+
+protected:
+ // BBTBuff interface exposed to actual implementations of IBBTBuffTrxLog
+
+ int Cpg() const { return m_pbbtbuff->Cpg(); }
+ CPAGE& BBTBuffCpage( int ipg ) { return m_pbbtbuff->Pcsr( ipg )->Cpage(); }
+};
+
+// Helper class to manage CoordinatedDirty on a BBTBuff.
+// If commit isn't called, the dbtimes will be reverted back by the destructor.
+class DbTimeGuard
+{
+ BBTBuff* m_pbbtBuff;
+ DBTIME m_dbtimeBefore;
+ ULONG m_fPageFlags;
+
+public:
+ DbTimeGuard( BBTBuff* pbbtBuff ) :
+ m_pbbtBuff( pbbtBuff ),
+ m_dbtimeBefore( pbbtBuff->m_pcsrBase->Dbtime() )
+ {}
+
+ void CoordinatedDirty( DBTIME dbtime )
+ {
+ m_fPageFlags = m_pbbtBuff->m_pcsrBase->Cpage().FFlags();
+ Assert( ( m_fPageFlags & CPAGE::fPageBBTBuffRoot ) && ( m_fPageFlags & CPAGE::fPageBBTBuff ) );
+ m_fPageFlags &= ( ~CPAGE::fPageBBTBuffRoot ); // Remove flag because it should only be present on the base page
+
+ // Requires pageset to be setup correctly
+ dbtime == dbtimeNil ? m_pbbtBuff->m_pcsrBase->Dirty() : m_pbbtBuff->m_pcsrBase->CoordinatedDirty( dbtime );
+ dbtime = m_pbbtBuff->m_pcsrBase->Dbtime();
+
+ for ( int i = 0; i < m_pbbtBuff->Cpg() - 1; i++ )
+ {
+ Assert( m_fPageFlags == m_pbbtBuff->m_rgcsrLatched[ i ].Cpage().FFlags() );
+ Assert( m_pbbtBuff->m_rgcsrLatched[ i ].Dbtime() == m_dbtimeBefore );
+ m_pbbtBuff->m_rgcsrLatched[ i ].CoordinatedDirty( dbtime );
+ }
+ }
+
+ void Commit() { m_dbtimeBefore = dbtimeNil; }
+ ~DbTimeGuard()
+ {
+ if ( m_dbtimeBefore != dbtimeNil )
+ {
+ // DbTimeGuard doesn't protect against page flag modifications.
+ // BBTBuff doesn't modify any page flags during its write operations.
+
+ m_pbbtBuff->m_pcsrBase->RevertDbtime( m_dbtimeBefore, m_fPageFlags | CPAGE::fPageBBTBuffRoot );
+ for ( int i = 0; i < m_pbbtBuff->Cpg() - 1; i++ )
+ {
+ m_pbbtBuff->m_rgcsrLatched[ i ].RevertDbtime( m_dbtimeBefore, m_fPageFlags );
+ }
+ }
+ }
+
+ DBTIME DbtimeBefore()
+ {
+ Assert( m_dbtimeBefore >= dbtimeStart );
+ return m_dbtimeBefore;
+ }
+
+ DBTIME DbtimeNew()
+ {
+ Assert( m_dbtimeBefore >= dbtimeStart );
+ return m_pbbtBuff->m_pcsrBase->Dbtime();
+ }
+};
+
+// A simple iterator over a sequence of SkipListNode*
+// The iterator starts positioned before the first element (like c# IEnumerator). Call Next() before calling Curr().
+// Provides a level of indirection to implement more complex iterators over a sequence of SkipListNode*
+// (required by FT Split/Evict)
+// can be generalized using standard c++ iterators and a type-erasing any_iterator
+class INodeSequence
+{
+public:
+ virtual const SkipListNode* Curr() = 0;
+ virtual bool Next() = 0;
+ virtual void Reset() = 0;
+};
+
+// A node sequence over a BBTBuff
+class NodeSequenceBBTBuff : public INodeSequence
+{
+ BBTBuff& m_bbtbuff;
+ SkipListLink m_linkFirst;
+ BBTBuff::SeekFlags m_fSeekFlags;
+ bool m_fBeforeFirst; // BBTBuff doesn't support BeforeFirst cursor position
+
+public:
+ NodeSequenceBBTBuff( BBTBuff& bbtbuff, BBTBuff::SeekFlags fFlags ) :
+ m_bbtbuff( bbtbuff ),
+ m_linkFirst( bbtbuff.GetLinkToCurrNode() ),
+ m_fSeekFlags( fFlags ),
+ m_fBeforeFirst( true )
+ {}
+
+ virtual const SkipListNode* Curr() { return ( !m_fBeforeFirst ? m_bbtbuff.PnodeCurr() : NULL ); }
+ virtual bool Next()
+ {
+ if ( !m_fBeforeFirst )
+ {
+ ERR err = m_bbtbuff.ErrMoveNext( m_fSeekFlags );
+ if ( err != errBBTNodeNotFound )
+ {
+ EnforceSz( err >= JET_errSuccess, "NodeSequenceBBTBuff_MoveNext" );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ m_fBeforeFirst = false;
+ return true;
+ }
+ }
+
+ virtual void Reset()
+ {
+ ERR err = m_bbtbuff.ErrSetCurrNodeFromLink( m_linkFirst );
+ EnforceSz( err >= JET_errSuccess, "NodeSequenceBBTBuff_Reset" );
+ m_fBeforeFirst = true;
+ }
+};
+
+// Provides transacted writes on a BBTBuff.
+template
+class BBTBuffWriter
+{
+private:
+ BBTBuff* m_pbbtbuff;
+ IBBTBuffTrxLog* m_pTrxLogger;
+
+public:
+ BBTBuffWriter( BBTBuff* pbbtbuff, IBBTBuffTrxLog* pTrxLogger ) :
+ m_pbbtbuff( pbbtbuff ),
+ m_pTrxLogger( pTrxLogger )
+ {
+ Assert( pbbtbuff == pTrxLogger->m_pbbtbuff );
+ }
+
+private:
+ void CoordinatedDirty();
+ SkipListLink GetLinkNew( int cb );
+ ERR ErrReorg_ProcessDeletes(
+ _In_count_( cLinksDel ) SkipListLink* rgLinksDel,
+ const int cLinksDel,
+ _Out_ SkipListLink* plinkIbMerge );
+
+public:
+ ERR ErrUpgradeToWriteMode();
+ ERR ErrInsert( BBTBuffOpcode opcode, const KEY& key, const DATA& data, SkipListNodeFlags flags );
+ ERR ErrDelete( const KEY& key );
+ ERR ErrFlagDelete( SkipListLink link );
+ ERR ErrReorganize();
+
+
+ // APIs for Evict
+
+ ERR ErrRangeDelete( SkipListLink linkFirst, int cNodes ); // deletes a range of nodes defined by link, count
+
+ // Merges in the given sequence of nodes and deleting the nodes in the delete sequence, while potentially reorganizing the buffer if needed.
+ ERR ErrMergeAndDelNodes(
+ _In_count_( cNodesMerge ) const SkipListNode** rgNodesMerge,
+ _In_count_( cNodesToDel ) SkipListLink* rgLinksDel,
+ const int cNodesMerge,
+ const int cNodesToDel,
+ _Out_ int* pcNodesMerged,
+ _Out_ int* pcNodesDel,
+ int cbReorgThreshold );
+};
+
+// Uses dbtime of the root to dirty the rest of the pages
+template
+void BBTBuffWriter::CoordinatedDirty()
+{
+ // All pages should be write-latched and root already dirtied
+ Assert( m_pbbtbuff->m_pcsrBase->FDirty() );
+ DBTIME dbtime = m_pbbtbuff->m_pcsrBase->Dbtime();
+
+ for ( int i = 0; i < m_pbbtbuff->Cpg() - 1; i++ )
+ {
+ m_pbbtbuff->m_rgcsrLatched[ i ].CoordinatedDirty( dbtime, bfdfDirty );
+ }
+}
+
+template
+ERR BBTBuffWriter::ErrUpgradeToWriteMode()
+{
+ ERR err = JET_errSuccess;
+
+ Assert( m_pbbtbuff->m_pcsrBase->FLatched() );
+ m_pbbtbuff->m_latchType = m_pbbtbuff->m_pcsrBase->Latch();
+
+ for ( int i = 0; i < m_pbbtbuff->Cpg(); i++ )
+ {
+ CSR* pcsr = m_pbbtbuff->Pcsr( i );
+ LATCH latchCurr = pcsr->Latch();
+ if ( latchCurr == latchReadTouch || latchCurr == latchReadNoTouch )
+ {
+ err = pcsr->ErrUpgradeFromReadLatch();
+ if ( err < JET_errSuccess )
+ {
+ // we lose our latch if the upgrade fails
+ // BBTBuff is unusable and we must release all latches.
+ for ( int j = 0; j < m_pbbtbuff->Cpg(); j++ )
+ {
+ m_pbbtbuff->Pcsr( j )->ReleasePage();
+ }
+
+ m_pbbtbuff->Unload();
+ return err;
+ }
+ }
+ else if ( latchCurr == latchRIW )
+ {
+ pcsr->UpgradeFromRIWLatch();
+ }
+ else
+ {
+ Assert( latchCurr == latchNone || latchCurr == latchWrite );
+ }
+ }
+
+ m_pbbtbuff->m_latchType = latchWrite;
+ return err;
+}
+
+template
+SkipListLink BBTBuffWriter::GetLinkNew( int cb )
+{
+ Assert( latchWrite == m_pbbtbuff->m_pcsrBase->Latch() );
+
+ BBTBuffHeader* pHeader = m_pbbtbuff->m_pHeader;
+ SkipListLink ibMicFree = pHeader->le_ibMicFree;
+ PageOffsetTuple pgOffset = m_pbbtbuff->IpgOffsetFromLink( pHeader->le_ibMicFree );
+ int cbUsed = SkipListLink::Roundup( cb ); // count wasted space too
+ Assert( cbUsed >= cb );
+
+ if ( cbUsed > m_pbbtbuff->IbPageDataEnd( pgOffset.ipg ) - pgOffset.ibOnPage )
+ {
+ if ( pgOffset.ipg < m_pbbtbuff->Cpg() - 1 )
+ {
+ pgOffset.ipg++;
+ ibMicFree = m_pbbtbuff->LinkFromIpgOffset( pgOffset.ipg, m_pbbtbuff->IbPageDataBegin( pgOffset.ipg ) );
+ }
+ else
+ {
+ // Caller should have checked for free space before calling this function
+ EnforceSz( false, "BBTBuff: errBBTBuffFull" );
+ }
+ }
+
+ // Caller should ensure that the page referenced by the returned link is latched
+ return ibMicFree;
+}
+
+// Inserts a new node into the list.
+// Duplicate nodes are inserted at the tail of a duplicate sequence.
+template
+ERR BBTBuffWriter::ErrInsert( BBTBuffOpcode opcode, const KEY& key, const DATA& data, SkipListNodeFlags flags )
+{
+ ERR err = JET_errSuccess;
+
+ m_pbbtbuff->ResetCurr();
+ Call( m_pbbtbuff->ErrWriteLatchAll() );
+
+ // Check/prepare for the insertion
+ // All modifications are deferred until we know that insert can succeed unconditionally
+ {
+ BBTBuffHeader* pHeader = m_pbbtbuff->m_pHeader;
+ BBTBuffChangeContext changeCtx{}; // zero-initializes
+ int level = m_pbbtbuff->GenLevel();
+ int cbNode = SkipListNode::Cb( level, key.Cb(), data.Cb() );
+
+ // Check for space and max supported node size.
+ if ( cbNode > m_pbbtbuff->CbMax() - pHeader->le_ibMicFree->ToInt() ||
+ cbNode > m_pbbtbuff->CbMaxNodeSize() )
+ {
+ // Check again with level 0 node.
+ level = 0;
+ cbNode = SkipListNode::Cb( level, key.Cb(), data.Cb() );
+ EnforceSz( cbNode <= m_pbbtbuff->CbMaxNodeSize(), "BBTBuff MaxNodeSizeExceeded" );
+
+ if ( cbNode > m_pbbtbuff->CbMax() - pHeader->le_ibMicFree->ToInt() )
+ {
+ Call( ErrERRCheck( errBBTBuffFull ) );
+ }
+ }
+
+ int result;
+ SkipListNode* rgNodes[ MAX_LEVELS ];
+ Call( m_pbbtbuff->ErrSeek_( key, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Curr, &result, changeCtx.rgLinksPrev, rgNodes ) );
+ bool fDuplicate = ( result == 0 );
+
+ // ErrSeek_() gives us the links to each node at every level at the insertion point.
+ // To insert, we only need to fix the links that are at the same level or below as the newly inserted node.
+
+ // Get node next to the insertion point at level 0
+ // This node's m_linkPrev0 pointer needs to be modified
+ SkipListLink linkNext0 = ( rgNodes[ 0 ] ? rgNodes[ 0 ]->LinkNext0() : RgSkipListLinksHead( pHeader )[ 0 ] );
+
+ SkipListLink linkNew = GetLinkNew( cbNode );
+ changeCtx.linkCurr = linkNew;
+ changeCtx.level = level;
+
+ // All preparation/checks succeeded
+ // LOG the insert operation
+ {
+ DbTimeGuard dbtimeGuard( m_pbbtbuff );
+ dbtimeGuard.CoordinatedDirty( m_pTrxLogger->m_dbtimeCoordinated );
+ changeCtx.dbtimeBefore = dbtimeGuard.DbtimeBefore();
+ changeCtx.dbtimeCurr = dbtimeGuard.DbtimeNew();
+
+ Call( m_pTrxLogger->ErrLogInsert( changeCtx, opcode, key, data, flags ) );
+ dbtimeGuard.Commit();
+ }
+
+ // WARNING: Can't fail after this point !!!
+ SkipListNode* pnodeNew = m_pbbtbuff->PnodeInsert_( changeCtx, rgNodes, opcode, key, data, flags, fDuplicate );
+
+ PageOffsetTuple pgOffsetNew = m_pbbtbuff->IpgOffsetFromLink( linkNew );
+ m_pbbtbuff->ChangeCurr( pgOffsetNew.ipg, pnodeNew );
+ Assert( linkNew == m_pbbtbuff->GetLinkToCurrNode() ); // sanity check
+ }
+
+HandleError:
+ m_pbbtbuff->DowngradeLatches();
+ return err;
+}
+
+template
+ERR BBTBuffWriter::ErrDelete( const KEY& key )
+{
+ ERR err = JET_errSuccess;
+
+ m_pbbtbuff->ResetCurr();
+ Call( m_pbbtbuff->ErrWriteLatchAll() );
+
+ // Check/Prepare for deletion
+ // All modifications are deferred until we know that delete can succeed unconditionally
+ {
+ int result;
+ BBTBuffChangeContext changeCtx{}; // zero-initializes
+ SkipListNode* rgNodes[ MAX_LEVELS ];
+ BBTBuffHeader* pHeader = m_pbbtbuff->m_pHeader;
+ Call( m_pbbtbuff->ErrSeek_( key, BBTBuff::SeekMode::LEQ, BBTBuff::SeekPos::Prev, &result, changeCtx.rgLinksPrev, rgNodes ) );
+
+ // ErrSeek_() will position at the node prev to the node to be deleted.
+ // result will tell us if the next node is an exact match or not.
+
+ if ( result == 0 )
+ {
+ // Get link to the node to delete.
+ SkipListLink linkDel = !changeCtx.rgLinksPrev[ 0 ].FNull() ? rgNodes[ 0 ]->LinkNext0() : RgSkipListLinksHead( pHeader )[ 0 ];
+ SkipListNode* pnodeToDelete = m_pbbtbuff->PnodeFromLink( linkDel );
+ Assert( pnodeToDelete != NULL );
+ Assert( pnodeToDelete->CmpKey( key ) == 0 );
+
+ changeCtx.linkCurr = linkDel;
+ changeCtx.level = pnodeToDelete->Level();
+
+ // The seek loop above guarantees that we always land at the latest node in a duplicate sequence.
+ // Enforce that. Deleting a node that isn't the latest duplicate version will cause corruption !
+ Call( m_pbbtbuff->ErrAssertIsLatestInDuplicateSequence( pnodeToDelete ) );
+ EnforceSz( !pnodeToDelete->FDuplicateNext0(), "BBTBuff::Delete_BadDupFlag" );
+
+ // All preparation/checks succeeded
+ // LOG delete operation
+ {
+ DbTimeGuard dbtimeGuard( m_pbbtbuff );
+ dbtimeGuard.CoordinatedDirty( m_pTrxLogger->m_dbtimeCoordinated );
+ changeCtx.dbtimeBefore = dbtimeGuard.DbtimeBefore();
+ changeCtx.dbtimeCurr = dbtimeGuard.DbtimeNew();
+
+ Call( m_pTrxLogger->ErrLogDelete( changeCtx, pnodeToDelete ) );
+ dbtimeGuard.Commit();
+ }
+
+ // WARNING: Can't fail after this point !!!
+ m_pbbtbuff->Delete_( changeCtx, rgNodes, pnodeToDelete );
+ }
+ else
+ {
+ err = ErrERRCheck( errBBTNodeNotFound );
+ }
+ }
+
+HandleError:
+ m_pbbtbuff->DowngradeLatches();
+ return err;
+}
+
+template
+ERR BBTBuffWriter::ErrFlagDelete( SkipListLink link )
+{
+ ERR err = JET_errSuccess;
+ Call( m_pbbtbuff->ErrWriteLatchAll() );
+ m_pbbtbuff->m_pcsrBase->Dirty();
+ CoordinatedDirty();
+
+ SkipListNode* pnode = m_pbbtbuff->PnodeFromLink( link );
+ pnode->SetDeleted( true );
+
+HandleError:
+ m_pbbtbuff->DowngradeLatches();
+ return err;
+}
+
+template
+ERR BBTBuffWriter::ErrReorganize()
+{
+ int cNodesMerged = 0;
+ int cNodesDel = 0;
+ ERR err = ErrMergeAndDelNodes( NULL, NULL, 0, 0, &cNodesMerged, &cNodesDel, -m_pbbtbuff->CbMax() ); // always reorg
+ Assert( cNodesMerged == 0 );
+ Assert( cNodesDel == 0 );
+ return err;
+}
+
+template
+ERR BBTBuffWriter::ErrRangeDelete( SkipListLink linkFirst, int cNodes )
+{
+ ERR err = JET_errSuccess;
+
+ m_pbbtbuff->AssertLatchedAll( latchWrite ); // not dirty yet
+ DbTimeGuard dbtimeGuard( m_pbbtbuff );
+ dbtimeGuard.CoordinatedDirty( m_pTrxLogger->m_dbtimeCoordinated );
+ DBTIME dbtimeBefore = dbtimeGuard.DbtimeBefore();
+ DBTIME dbtimeCurr = dbtimeGuard.DbtimeNew();
+
+ CallR( m_pTrxLogger->ErrLogRangeDelete( dbtimeBefore, dbtimeCurr, linkFirst, cNodes ) );
+ dbtimeGuard.Commit();
+
+ m_pbbtbuff->RangeDelete_( linkFirst, cNodes );
+ return err;
+}
+
+// Returns the cost of doing a full reorg relative to doing inplace operations.
+// where cNodesTotal is the total nodes in a BBTBuff,
+// and the return value is the number of nodes to inplace delete/insert to match that cost.
+// For example, for input -> out
+// 0 -> 0
+// 100 -> 15
+// 500 -> 55
+// 1000 -> 100
+// 2500 -> 221
+// 5000 -> 406
+INLINE int CalcSkipListMergeHeuristic( int n )
+{
+ // Skiplist has avg insert/delete performance of log2(n)
+ // Each reorg requires individually visiting every node and copying it (n operations).
+ // Then copying back the reorg-ed buffers.
+ // Assume that the nodes are small enough that cost of copying is negligible compared to visiting the node.
+ // So if n = log2(n) * cOPs (where cOPs = the number of inplace ops).
+ // return cOps = n / log2(n)
+ const double log10Of2 = 0.30102999566398119521373889472449;
+ return n > 0 ? static_cast( n / ( log10( n ) / log10Of2 ) ) : 0;
+}
+
+// Reorganize and merge: Merges incoming nodes in pseqNodesMerge while deleting local nodes specified by pseqNodesDel.
+// 1. Makes a logical copy of the list by allocating new page sized buffers on the heap
+// and copying over all the nodes.
+// - If copying is impossible or inefficient, does an inplace merge-delete.
+// - Caller can specify cbReorgthreshold to force a reorg if doing a reorg would return atleast that much empty space.
+// 2. Merges nodes in pseqNodesMerge into the copied list. Merge sequence must be sorted.
+// 3. Removes any local nodes that are in the delete sequence. Del sequence must be sorted.
+// 4. The new pages are mem-copied back into the cpage buffers.
+// 5. The BBTBuff header is adjusted to reflect the new reality, in the end.
+template
+ERR BBTBuffWriter::ErrMergeAndDelNodes(
+ _In_count_( cNodesMerge ) const SkipListNode** rgNodesMerge,
+ _In_count_( cNodesToDel ) SkipListLink* rgLinksDel,
+ const int cNodesMerge,
+ const int cNodesToDel,
+ _Out_ int* pcNodesMerged,
+ _Out_ int* pcNodesDel,
+ int cbReorgThreshold )
+{
+ Assert( pcNodesMerged != NULL );
+ Assert( pcNodesDel != NULL );
+ m_pbbtbuff->AssertLatchedAll( latchWrite ); // not dirty yet
+ m_pbbtbuff->ResetCurr();
+
+ ERR err = JET_errSuccess;
+ BYTE** rgpbPage = NULL;
+ SkipListLink linkIbMergeStart( 0 );
+ const int cMaxPages = m_pbbtbuff->Cpg();
+
+ Call( m_pbbtbuff->ErrWriteLatchAll() );
+
+ err = ErrReorg_ProcessDeletes( rgLinksDel, cNodesToDel, &linkIbMergeStart );
+
+ if ( err == errBBTBuffFull )
+ {
+ // Reorg can't be done because existing data expanded because of skiplist leveling
+ // and there weren't enough deleted nodes to cover the difference.
+ *pcNodesDel = 0;
+ *pcNodesMerged = 0;
+ goto HandleError;
+ }
+
+ const int cbReorgGained = m_pbbtbuff->m_pHeader->le_ibMicFree->ToInt() - linkIbMergeStart.ToInt(); // can be negative
+ if ( cbReorgGained < cbReorgThreshold )
+ {
+ const int heuristic = CalcSkipListMergeHeuristic( m_pbbtbuff->CNodes() );
+ if ( cNodesToDel < heuristic )
+ {
+ // We may be doing too less to do a full reorg.
+ // Calculate approx count of merges too.
+ int cbLeftReorg = m_pbbtbuff->CbMax() - linkIbMergeStart.ToInt();
+ int cbLeftNoReorg = m_pbbtbuff->CbMax() - m_pbbtbuff->m_pHeader->le_ibMicFree->ToInt();
+ int cOpsReorg = cNodesToDel;
+ int cOpsNoReorg = cNodesToDel;
+
+ for ( int i = 0; i < cNodesMerge; i++ )
+ {
+ // Merge count is calculated off of cbLeft after reorg.
+ // It should be close to current cbFree (assuming we are doing few deletes, thats why we are here).
+ // In which case it doesn't matter much, or if we did delete some large node, then we assume that
+ // most nodes are small and cOpsExpected will climb higher than the heuristic, skipping in-place merge.
+ const SkipListNode* pnodeMerge = rgNodesMerge[ i ];
+ const int cb = SkipListNode::Cb( cOpsReorg, pnodeMerge->CbKey(), pnodeMerge->CbData() );
+ cbLeftReorg -= cb;
+ cbLeftNoReorg -= cb;
+
+ if ( cbLeftNoReorg >= 0 )
+ {
+ cOpsNoReorg++;
+ }
+
+ if ( cbLeftReorg < 0 || cOpsReorg > heuristic ) // count 1 over the heuristic
+ {
+ break;
+ }
+
+ cOpsReorg++;
+ }
+
+ // UA_TODO: this works well for small sized nodes. Too much variance in node sizes, or large nodes will cause problems.
+ // For example, lets say we delete 1 large node on a full bbtbuff, and try to merge in a few small nodes.
+ // The merge might not be possible without reorg, but we will try to do an inplace merge.
+ // This atleast makes forward progress (the large node will be deleted, but no merges will be done).
+ // The next evict will have more forward progress.
+
+ // UA_TODO: Enable code below. Needs logging support for in-place merge and del.
+ //if ( cOpsReorg < heuristic && cOpsNoReorg == cOpsReorg )
+ //{
+ // // If we are doing a small number of merge and deletes then use in-place merge,
+ // // and we can do the same number of operations with a reorg.
+ // Call( ErrInplaceMergeAndDelNodes( rgNodesMerge, rgNodesDel, cNodesMerge, cNodesDel, pcNodesMerged, pcNodesDel ) );
+ // goto HandleError;
+ //}
+ }
+ }
+
+ Alloc( rgpbPage= (BYTE**) _alloca( sizeof(BYTE*) * cMaxPages ) );
+ for ( int i = 0; i < cMaxPages; i++ )
+ {
+ BFAlloc( bfasTemporary, (void**) &rgpbPage[ i ], m_pbbtbuff->m_pcsrBase->Cpage().CbPage() );
+ Alloc( rgpbPage[ i ] );
+ }
+
+ int cNodesMerged = 0;
+ int cNodesDeleted = 0;
+ m_pbbtbuff->CopyMergeAndDelNodes_(
+ rgpbPage,
+ rgNodesMerge,
+ rgNodesMerge + cNodesMerge,
+ rgLinksDel,
+ rgLinksDel + cNodesToDel,
+ linkIbMergeStart,
+ &cNodesMerged,
+ &cNodesDeleted );
+
+ // The skip list has been copied and reogranized
+ // Dirty all pages to copy back to the original
+ // WARNING: All local node pointers (e.g. in the merge, del sequences) are invalid after this point.
+ // LOG the MergeAndDel operation
+ {
+ DbTimeGuard dbtimeGuard( m_pbbtbuff );
+ dbtimeGuard.CoordinatedDirty( m_pTrxLogger->m_dbtimeCoordinated );
+ DBTIME dbtimeBefore = dbtimeGuard.DbtimeBefore();
+ DBTIME dbtimeCurr = dbtimeGuard.DbtimeNew();
+
+ Call( m_pTrxLogger->ErrLogMergeAndDel(
+ dbtimeBefore,
+ dbtimeCurr,
+ rgNodesMerge,
+ rgLinksDel,
+ cNodesMerged,
+ cNodesDeleted,
+ linkIbMergeStart ) );
+ dbtimeGuard.Commit();
+ }
+
+ // WARNING: Can't fail after this point !!!
+ *pcNodesMerged = cNodesMerged;
+ *pcNodesDel = cNodesDeleted;
+
+ // Copy root page (BBTBuffHeader + any data)
+ memcpy(
+ m_pbbtbuff->PbPage( 0 ) + m_pbbtbuff->IbHeader(),
+ rgpbPage[ 0 ] + m_pbbtbuff->IbHeader(),
+ m_pbbtbuff->PFormat()->cbBBTRoot );
+
+ // if the last node fits perfectly at the end of the last page, ibMicFree can point to the next page
+ int ipgLast = min( cMaxPages - 1, m_pbbtbuff->IpgOffsetFromLink( m_pbbtbuff->m_pHeader->le_ibMicFree ).ipg );
+ for ( int i = 1; i <= ipgLast; i++ )
+ {
+ // Copy back the page at the appropriate offset
+ int cbCopy = m_pbbtbuff->IbPageDataEnd( i ) - m_pbbtbuff->IbPageDataBegin( i );
+ memcpy(
+ m_pbbtbuff->PbPage( i ) + m_pbbtbuff->IbPageDataBegin( i ),
+ rgpbPage[ i ] + m_pbbtbuff->IbPageDataBegin( i ),
+ cbCopy );
+ }
+
+ // UA_TODO: pattern-fill leftover pages
+
+ // Return a warning if we couldn't merge in all of the external nodes.
+ if ( *pcNodesMerged < cNodesMerge )
+ {
+ err = ErrERRCheck( wrnBBTMergeTargetFull );
+ }
+
+HandleError:
+ // Cleanup allocated memory
+ if ( rgpbPage )
+ {
+ for ( int i = 0; i < cMaxPages; i++ )
+ {
+ BFFree( rgpbPage[ i ] );
+ }
+ }
+
+ return err;
+}
+
+template
+ERR BBTBuffWriter::ErrReorg_ProcessDeletes(
+ _In_count_( cLinksDel ) SkipListLink* rgLinksDel,
+ const int cLinksDel,
+ _Out_ SkipListLink* plinkIbMerge )
+{
+ ERR err = JET_errSuccess;
+ BBTBuffHeader* pHeader = m_pbbtbuff->m_pHeader;
+ SkipListNode* pnodeCurr;
+ SkipListLink linkDelCurr = ( cLinksDel > 0 ? rgLinksDel[ 0 ] : SkipListLink::Null() );
+ SkipListLink linkCurr = RgSkipListLinksHead( pHeader )[ 0 ];
+ SkipListLink ibCurr = SkipListLink::FromInt( sizeof( BBTBuffHeader ) ); // leave space for the header
+ int cNodesLeft = 0;
+ int iLinkDel = 0;
+
+ Assert( latchWrite == m_pbbtbuff->m_pcsrBase->Latch() );
+
+ while ( !linkCurr.FNull() )
+ {
+ pnodeCurr = m_pbbtbuff->PnodeFromLink( linkCurr );
+ if ( linkCurr != linkDelCurr )
+ {
+ const int level = m_pbbtbuff->GenLevel( cNodesLeft ); // Re-level deterministically because we know the node count, and we are appending sequentially
+ const int cb = SkipListNode::Cb( level, pnodeCurr->CbKey(), pnodeCurr->CbData() );
+ const int cbUsed = SkipListLink::Roundup( cb ); // count wasted space too
+
+ PageOffsetTuple pgOffsetCurr = m_pbbtbuff->IpgOffsetFromLink( ibCurr );
+ const int cbLeft = ( pgOffsetCurr.ipg < m_pbbtbuff->Cpg() ? m_pbbtbuff->IbPageDataEnd( pgOffsetCurr.ipg ) - pgOffsetCurr.ibOnPage : 0 );
+ if ( cbUsed > cbLeft )
+ {
+ pgOffsetCurr.ipg++;
+ if ( pgOffsetCurr.ipg >= m_pbbtbuff->Cpg() )
+ {
+ // We haven't added any extra nodes. But overflowed because of different skiplist leveling.
+ Call( ErrERRCheck( errBBTBuffFull ) );
+ }
+
+ pgOffsetCurr.ibOnPage = (USHORT) m_pbbtbuff->IbPageDataBegin( pgOffsetCurr.ipg );
+ ibCurr = m_pbbtbuff->LinkFromIpgOffset( pgOffsetCurr.ipg, pgOffsetCurr.ibOnPage );
+ }
+
+ ibCurr.Inc( cbUsed );
+ cNodesLeft++;
+ }
+ else
+ {
+ iLinkDel++;
+ linkDelCurr = ( iLinkDel < cLinksDel ? rgLinksDel[ iLinkDel ] : SkipListLink::Null() );
+ }
+
+ linkCurr = pnodeCurr->LinkNext0();
+ }
+
+ Assert( linkDelCurr.FNull() ); // all deleted nodes should've been matched
+ Assert( iLinkDel == cLinksDel );
+
+ // When we reorg, node sizes may increase (because of different skiplist leveling).
+ Assert( cNodesLeft == pHeader->le_cNodes - iLinkDel );
+ *plinkIbMerge = ibCurr;
+
+HandleError:
+ return err;
+}
diff --git a/dev/ese/src/inc/bt.hxx b/dev/ese/src/inc/bt.hxx
index fb831eb2..eca5784c 100644
--- a/dev/ese/src/inc/bt.hxx
+++ b/dev/ese/src/inc/bt.hxx
@@ -312,13 +312,13 @@ struct PrereadInfo
ERR ErrBTIMultipageCleanup(
- FUCB * const pfucb,
- const BOOKMARK& bm,
- BOOKMARK * const pbmNext,
- RECCHECK * const preccheck,
- MERGETYPE * const pmergetype,
- const BOOL fRightMerges,
- __inout_opt PrereadInfo * const pPrereadInfo = NULL );
+ FUCB * const pfucb,
+ const BOOKMARK& bm,
+ BOOKMARK * const pbmNext,
+ RECCHECK * const preccheck,
+ MERGETYPE * const pmergetype,
+ const BOOL fRightMerges,
+ __inout_opt PrereadInfo * const pPrereadInfo = NULL );
ERR ErrBTPageMove(
_In_ FUCB * const pfucb,
@@ -326,9 +326,15 @@ ERR ErrBTPageMove(
_In_ const PGNO pgnoSource,
_In_ const BOOL fLeafPage,
_In_ const ULONG fSPAllocFlags,
- __inout BOOKMARK * const pbmNext );
+ _Inout_ BOOKMARK * const pbmNext );
VOID BTPerformPageMove( _In_ MERGEPATH * const pmergePath );
+ERR ErrBTContiguousExtentMove(
+ _In_ FUCB * const pfucb,
+ _In_ const BOOKMARK& bm,
+ _In_ const PGNO pgnoSourceFirst,
+ _Out_ CPG * const pcpgMoved );
+
ERR ErrBTFindFragmentedRange(
_In_ FUCB * const pfucb,
_In_ const BOOKMARK& bmStart,
diff --git a/dev/ese/src/inc/ccsr.hxx b/dev/ese/src/inc/ccsr.hxx
index 40240e8c..b08228e6 100644
--- a/dev/ese/src/inc/ccsr.hxx
+++ b/dev/ese/src/inc/ccsr.hxx
@@ -58,7 +58,6 @@ class CSR
DBTIME Dbtime( ) const;
VOID SetDbtime( const DBTIME dbtime );
VOID RevertDbtime( const DBTIME dbtime, const ULONG fFlags );
- VOID RestoreDbtime( const DBTIME dbtime, const BOOL fPageFDPDeleteBefore );
BOOL FLatched( ) const;
LATCH Latch( ) const;
PGNO Pgno( ) const;
@@ -237,9 +236,14 @@ class CSR
const VOID * PvBufferForCrashDump() { return m_cpage.PvBuffer(); }
#ifdef DEBUGGER_EXTENSION
+ VOID LoadDehydratedPage( const IFMP ifmp, const PGNO pgno, VOID* const pv, const ULONG cb, const ULONG cbPage );
VOID Dump( CPRINTF * pcprintf, DWORD_PTR dwOffset = 0 ) const;
#endif // DEBUGGER_EXTENSION
+#ifdef ENABLE_JET_UNIT_TEST
+ VOID LoadNewTestPage( const ULONG cb, const IFMP ifmp = ifmpNil, const PGNO pgno = 42 );
+#endif // ENABLE_JET_UNIT_TEST
+
private:
CSR( const CSR& ); // not defines
@@ -424,11 +428,11 @@ VOID CSR::SetDbtime( const DBTIME dbtime )
}
INLINE
-VOID CSR::OverrideDbtime_( const DBTIME dbtime, const ULONG fFlags )
+VOID CSR::RevertDbtime( const DBTIME dbtime, const ULONG fFlags )
{
ASSERT_VALID( this );
Assert( FDirty() );
-
+
Assert( Latch() == latchWrite );
Assert( dbtime <= m_dbtimeSeen );
@@ -438,21 +442,6 @@ VOID CSR::OverrideDbtime_( const DBTIME dbtime, const ULONG fFlags )
Assert( dbtime == m_cpage.Dbtime() );
}
-INLINE
-VOID CSR::RevertDbtime( const DBTIME dbtime, const ULONG fFlags )
-{
- Assert( PinstFromIfmp( m_cpage.Ifmp() )->m_plog->FRecoveringMode() != fRecoveringRedo ); // redo gets all preconditions done, and never has to revert.
- OverrideDbtime_( dbtime, fFlags );
-}
-
-INLINE
-VOID CSR::RestoreDbtime( const DBTIME dbtime, const BOOL fPageFDPDeleteBefore )
-{
- Assert( m_cpage.FLoadedPage() );
- Assert( PinstFromIfmp( m_cpage.Ifmp() )->m_plog->FRecoveringMode() == fRecoveringRedo );
- OverrideDbtime_( dbtime, m_cpage.FFlags() | ( fPageFDPDeleteBefore ? CPAGE::fPageFDPDelete : 0 ) );
-}
-
#ifdef DEBUG
@@ -811,6 +800,26 @@ INLINE ERR CSR::ErrLoadPage(
}
+#ifdef ENABLE_JET_UNIT_TEST
+INLINE VOID CSR::LoadNewTestPage( const ULONG cb, const IFMP ifmp /* = ifmpNil */, const PGNO pgno /* = 42 */ )
+{
+ ASSERT_VALID( this );
+ Assert( m_latch == latchNone );
+
+ m_cpage.LoadNewTestPage( cb, ifmp, pgno );
+
+ // set members
+ m_pgno = m_cpage.PgnoThis();
+ m_cpage.SetDbtime( dbtimeStart );
+ m_dbtimeSeen = m_cpage.Dbtime();
+ m_latch = latchWrite;
+ m_pagetrimState = pagetrimNormal;
+
+ Assert( m_dbtimeSeen == m_cpage.Dbtime() );
+}
+#endif // ENABLE_JET_UNIT_TEST
+
+
INLINE VOID CSR::CopyPage( const VOID* pvPage, const ULONG cbPage )
{
ASSERT_VALID( this );
@@ -1168,3 +1177,35 @@ VOID CSR::Reset()
m_dbtimeSeen = dbtimeNil;
m_pagetrimState = pagetrimNormal;
}
+
+// Variable sized CSR array.
+// Use with alloca to create a CSR array on stack.
+// Automatically releases any held latches.
+template
+class CSRArray : public FixedArray