2025-04-27 07:49:33 -04:00

500 lines
13 KiB
C++

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// S H L K C A C H E . H
//
// Declarations for objects existing in shared memory and
// supporting the shared lock cache implementation.
//
// Classes defined here are:
// CInShBytes = allocates bytes in shared memory.
// CInShString = allocates strings in shared memory.
// CInShLockData = handles all the information about
// a particular lock for a resource.
// CInShCacheStatic = holds all static information needed
// to use the shared cache.
// CInShLockCache = holds the hash table for the shared
// memory cache.
//
// Copyright 2000 Microsoft Corporation, All Rights Reserved
//
#ifndef _SHLKCACHE_H_
#define _SHLKCACHE_H_
#include <smh.h>
#include <sz.h>
#include "pipeline.h"
//==================================
// Forward Declarations for classes
//==================================
class CInShLockCache;
class CInShCacheStatic;
class CInShLockData;
//==================================
// Global Function Declarations
//==================================
// InitalizeSharedCache is implemented in the initobj.cpp file
// as part of the _shlkcache library.
//
HRESULT InitalizeSharedCache(SharedPtr<CInShLockCache>& spSharedCache
, SharedPtr<CInShCacheStatic>& spSharedStatic
, BOOL fCreateFile);
// Callback for printing out lock information.
//
typedef VOID CALLBACK EmitLockInfoDecl(SharedPtr<CInShLockData>* plock, LPVOID pContext );
//==================================
// Class Declarations
//==================================
//
// Class CInShBytes
//
// Allows for dynamic creation of an array of bytes in shared
// memory. However, the array is write once, read while holding
// a reference to the object. Data is not copied when handed out.
//
class CInShBytes
{
private:
// m_HandleToMemory is really an offset into the shared memory
// heap supported by smh.h.
//
SHMEMHANDLE m_HandleToMemory;
// NOT IMPLEMENTED
//
CInShBytes& operator=( const CInShBytes& );
CInShBytes( const CInShBytes& );
public:
CInShBytes();
void CopyInBytes(LONG i_cbMemory, LPVOID i_pvMemory);
LPCVOID GetPtrToBytes();
LPVOID GetPtrToBytes(LONG i_cbMemory);
~CInShBytes();
};
//
// Class CInShString
//
// Allows for dynamic creation of a LPWSTR in shared memory. However, the
// string is write once, read while holding a reference to the object. Data
// is not copied when handed out.
//
class CInShString : CInShBytes
{
private:
// NOT IMPLEMENTED
//
CInShString& operator=( const CInShString& );
CInShString( const CInShString& );
public:
CInShString() {}
~CInShString()
{
}
LPCWSTR GetPtrToString()
{
return (LPCWSTR) GetPtrToBytes();
}
void CopyInString(LPCWSTR i_pStr)
{
if (i_pStr!=NULL)
CopyInBytes(static_cast<LONG>(wcslen(i_pStr)+1) * sizeof(WCHAR), (LPVOID) i_pStr);
else
CopyInBytes(0, NULL);
}
// Static helper function to get a ptr to a shared memory string
// when all we have is the shared handle to the CInShString object.
//
static LPCWSTR GetPtrToStringFromHandle(SharedHandle<CInShString>& shStringHandle)
{
LPCWSTR pRetVal = NULL;
SharedPtr<CInShString> spString;
if (spString.FBind(shStringHandle))
{
pRetVal = spString->GetPtrToString();
}
return pRetVal;
};
};
//
// Class CInShString
//
// Holds all information about a shared lock as it pertains to a resource.
//
class CInShLockData
{
public:
enum { MAX_LOCKTOKEN_LENGTH = 256 };
enum { DEFAULT_LOCK_TIMEOUT = 60 * 3 };
private:
__int64 m_i64LockID;
// Handles to dynamic sized memory for the class
//
SharedHandle<CInShString> m_hOffsetToResourceString;
SharedHandle<CInShString> m_hOffsetToOwnerComment;
SharedHandle<CInShBytes> m_hOffsetToSidOwner;
// Lock description data
//
DWORD m_dwAccess;
DWORD m_dwLockType;
DWORD m_dwLockScope;
DWORD m_dwSecondsTimeout;
// File handle that DAVProc is holding
// to keep the file open. It must be
// duphandled before using.
//
HANDLE m_hDAVProcFileHandle;
// Lock Cache Keys
//
DWORD m_dwNameHash;
DWORD m_dwIDHash;
// Lock Cache Timeout data
//
FILETIME m_fRememberFtNow;
FILETIME m_ftLastAccess;
BOOL m_fHasTimedOut;
// Links for hash table collision support
//
SharedHandle<CInShLockData> m_hNextName;
SharedHandle<CInShLockData> m_hNextID;
// Unique Lock Token Identifier
//
WCHAR m_rgwchToken[MAX_LOCKTOKEN_LENGTH];
// Used to save the owner sid with the lock
//
HRESULT SetLockOwnerSID(HANDLE hit);
public:
// CREATORS
//
CInShLockData();
~CInShLockData();
// Initalization functions:
//
// Used to setup an inital shared lock
// with the settings provided.
HRESULT Init ( LPCWSTR wszStoragePath
, DWORD dwAccess
, _int64 i64LockID
, LPCWSTR pwszGuid
, DWORD dwLockType = 0
, DWORD dwLockScope = 0
, DWORD dwTimeout = 0
, LPCWSTR wszOwnerComment = NULL
, HANDLE hit = INVALID_HANDLE_VALUE
);
// Used by lock manager to set the key values
// for the lock cache that this item will be stored at.
//
void SetHashes(DWORD dwIDValue, DWORD dwNameValue);
// Used by DAVProc to set in the DAVProc representation of the file handle.
//
void SetDAVProcFileHandle(HANDLE h)
{
Assert (m_hDAVProcFileHandle == INVALID_HANDLE_VALUE);
m_hDAVProcFileHandle = h;
};
// Hash functions:
BOOL IsEqualByID(__int64 i64LockID)
{ return (i64LockID == m_i64LockID); }
BOOL IsEqualByName(LPCWSTR wszResource, DWORD dwLockType);
DWORD GetIDHashCode() const
{ return m_dwIDHash; }
DWORD GetNameHashCode() const
{ return m_dwNameHash; }
// Timer Functions:
// Checks if a lock has expired.
//
BOOL IsExpired(FILETIME ftNow);
void SetLastAccess(FILETIME ft)
{ m_ftLastAccess = ft; }
// Last writer wins for changing the timeout.
//
VOID SetTimeoutInSecs(DWORD dwSeconds)
{ m_dwSecondsTimeout = dwSeconds; }
// Usage Functions:
HRESULT GetUsableHandle(HANDLE i_hDAVProcess, HANDLE* o_phFile);
const __int64 * GetLockID() const
{ return &m_i64LockID; }
DWORD GetTimeoutInSecs() const
{ return m_dwSecondsTimeout; }
DWORD GetLockType() const
{ return m_dwLockType; }
DWORD GetLockScope() const
{ return m_dwLockScope; }
DWORD GetAccess() const
{ return m_dwAccess; }
// This is a create once, don't change property.If you use this to get the
// resource name, do not release the handle on the object until you
// are done with this pointer into the object below.
//
LPCVOID GetOwnerSID()
{
SharedPtr<CInShBytes> pSID;
pSID.FBind(m_hOffsetToSidOwner);
if (!pSID.FIsNull())
return (LPVOID) (pSID->GetPtrToBytes());
return NULL;
}
// This is a create once, don't change property.If you use this to get the
// resource name, do not release the handle on the object until you are
// done with this pointer into the object below.
//
LPCWSTR PwszOwnerComment()
{
return CInShString::GetPtrToStringFromHandle(m_hOffsetToOwnerComment);
};
// This is a create once, don't change property.If you use this to get the
// resource name, do not release the handle on the object until you
// are done with this pointer into the object below.
//
LPCWSTR GetResourceName()
{
return CInShString::GetPtrToStringFromHandle(m_hOffsetToResourceString);
};
// Lock token string
//
LPCWSTR GetLockTokenString()
{
return m_rgwchToken;
}
VOID SetNextHandleByID(SharedHandle<CInShLockData>& shNext)
{
m_hNextID = shNext;
}
SharedHandle<CInShLockData>& GetNextHandleByID ()
{
return m_hNextID;
}
VOID SetNextHandleByName(SharedHandle<CInShLockData>& shNext)
{
m_hNextName = shNext;
}
SharedHandle<CInShLockData>& GetNextHandleByName ()
{
return m_hNextName;
}
};
//
// Class CInShCacheStatic
//
// Holds static information about the shared lock cache. Only one of these
// should ever be created and it should be created by DAVProc.
//
class CInShCacheStatic
{
private:
// Guid string for our lock ids.
//
WCHAR m_rgwchGuid[gc_cchMaxGuid];
// ProcessId of the DAVProc used for duplicating file handles.
//
DWORD m_DAVProcessId;
public:
// Counter keeping track of next id for a new lock token
//
LONG m_lTokenLow;
LONG m_lTokenHigh;
// Saves the current process's ID and a newly generated guid for use in
// creating and working with lock tokens.
//
CInShCacheStatic()
: m_lTokenLow(50)
, m_lTokenHigh(50)
{
m_DAVProcessId = GetCurrentProcessId();
UUID guid;
UuidCreate(&guid);
wsprintfW(m_rgwchGuid, gc_wszGuidFormat,
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
};
DWORD GetDAVProcessId() const
{ return m_DAVProcessId; }
LPCWSTR GetGuidString() const
{ return m_rgwchGuid; }
};
//
// Class CInShLockCache
//
// Holds the shared lock cache table that tracks all active locks
//
class CInShLockCache
{
// NOTE: The shared lock cache is double indexed by id and by name
// It needs to be indexed by name so we can quickly access
// properties about the lock for propfind when dealing only
// with the resource name.
// While we shouldn't need to index by the lock id (because we
// always have the resource string we are dealing with), it
// would mean more extensive changes to the lockmgr interface,
// the CLockCache class and code in all the DAV providers
// to change this over to not use ID. Since part of the goals
// of developing the shared lock cache is to touch as little
// shared project code, I am not making this change.
public:
enum { CACHE_SIZE = 37 };
private:
// CODEWORK: Evaluate performance and move to a better
// form of locking for the cache.
// The Shared lock cache is currently guarded by a spin
// lock stored in shared memory, it has no promotion so
// some mostly read activities like Expiring locks are
// all blocked with a write lock.
//
CSharedMRWLock m_lock;
// NOT IMPLEMENTED
//
CInShLockCache& operator=( const CInShLockCache& );
CInShLockCache( const CInShLockCache& );
// The lockmgr caches appeared to be variable size, but
// they are all ways created to be 37 locks, so the shared
// lock cache will not be variable size.
//
SharedHandle<CInShLockData> m_hIDEntries[CACHE_SIZE];
SharedHandle<CInShLockData> m_hNameEntries[CACHE_SIZE];
DWORD m_dwItemsInCache;
// Finds and Deletes the token from the name cache (does not touch the ID cache)
//
void DeleteByName ( LPCWSTR wszResource, __int64 i64LockID);
// Deletes a found token from the name cache.
//
VOID DeleteFromNameList(SharedPtr<CInShLockData>& spObjToDelete, SharedHandle<CInShLockData>& shObjBefore, DWORD dwIndexInCache);
// Deletes a found token from the ID cache.
//
VOID DeleteFromIDList(SharedPtr<CInShLockData>& spObjToDelete, SharedHandle<CInShLockData>& shObjBefore, DWORD dwIndexInCache);
// Find a lock when given it's resource name
//
BOOL FLookupByName( LPCWSTR wszResource
, DWORD dwLockType
, SharedPtr<CInShLockData>& plock );
public:
#ifdef DBG
// DebugFunction for seeing what is in the cache.
//
void DumpCache();
#endif
CInShLockCache();
~CInShLockCache();
void Add(SharedPtr<CInShLockData>& spSharedEntry);
BOOL FLookupByID( __int64 i64LockID, SharedPtr<CInShLockData>& plock );
BOOL FLookUpAll( LPCWSTR wszResource
, DWORD dwLockType
, BOOL fEmitXML
, LPVOID pContext
, EmitLockInfoDecl* pEmitLockInfo );
// Will also delete the token from the name cache.
//
void DeleteByID( __int64 i64LockID );
// Figure out a hash code based on the lock id.
//
DWORD GetHashCodeByID(__int64 i64LockID);
// Figure out a hash code based on the resource string.
//
DWORD GetHashCodeByName(LPCWSTR wszResource);
VOID ExpireLocks();
BOOL FEmpty() { return (0 == m_dwItemsInCache);}
};
#endif // _SHLKCACHE_H_ Define