195 lines
4.6 KiB
C++
195 lines
4.6 KiB
C++
|
/*===================================================================
|
||
|
Microsoft Denali
|
||
|
|
||
|
Microsoft Confidential.
|
||
|
Copyright 1997 Microsoft Corporation. All Rights Reserved.
|
||
|
|
||
|
Component: ID Generator
|
||
|
|
||
|
File: Idgener.cpp
|
||
|
|
||
|
Owner: DmitryR
|
||
|
|
||
|
This is the ID Generator source file.
|
||
|
===================================================================*/
|
||
|
#include "denpre.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "Idgener.h"
|
||
|
|
||
|
#include "memchk.h"
|
||
|
|
||
|
/*===================================================================
|
||
|
CIdGenerator::CIdGenerator
|
||
|
|
||
|
NOTE: Constructor
|
||
|
|
||
|
Parameters:
|
||
|
|
||
|
Returns:
|
||
|
===================================================================*/
|
||
|
CIdGenerator::CIdGenerator()
|
||
|
: m_fInited(FALSE),
|
||
|
m_dwStartId(0),
|
||
|
m_dwLastId(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/*===================================================================
|
||
|
CIdGenerator::~CIdGenerator()
|
||
|
|
||
|
NOTE: Destructor
|
||
|
|
||
|
Parameters:
|
||
|
|
||
|
Returns:
|
||
|
===================================================================*/
|
||
|
CIdGenerator::~CIdGenerator()
|
||
|
{
|
||
|
if ( m_fInited )
|
||
|
DeleteCriticalSection( &m_csLock );
|
||
|
}
|
||
|
|
||
|
/*===================================================================
|
||
|
HRESULT CIdGenerator::Init()
|
||
|
|
||
|
NOTE: Seed new starting Id
|
||
|
|
||
|
Parameters:
|
||
|
|
||
|
Returns: HRESULT (could fail to create critical section)
|
||
|
===================================================================*/
|
||
|
HRESULT CIdGenerator::Init()
|
||
|
{
|
||
|
Assert(!m_fInited);
|
||
|
|
||
|
/*===
|
||
|
|
||
|
Seed the starting id
|
||
|
The starting Id should be:
|
||
|
1) random
|
||
|
2) not to close to recently generated starting ids
|
||
|
To accomplish the above, starting Id is in the
|
||
|
following (binary) format:
|
||
|
|
||
|
00TT.TTTT TTTT.TTTT TTT1.RRRR RRRR.RRRR
|
||
|
|
||
|
RRR is random number to introduce some
|
||
|
randomness
|
||
|
|
||
|
1 is needed to make sure the id is far
|
||
|
enough from 0
|
||
|
|
||
|
TTT is current time() in 4 second increments.
|
||
|
This means that 4 second in server restart
|
||
|
delay translates into 8,192 difference in
|
||
|
the starting Id (122880 sessions / minute).
|
||
|
17 bits of 4 sec intervals make a roll over
|
||
|
time of about 145 hours, hopefully longer
|
||
|
than a client's connection lifetime (not
|
||
|
that it REALLY matters).
|
||
|
|
||
|
00 in the highest bits is to make sure it
|
||
|
doesn't reach 0xffffffff too soon
|
||
|
|
||
|
===*/
|
||
|
|
||
|
DWORD dwRRR = rand() & 0x00000FFF;
|
||
|
DWORD dwTTT = (((DWORD)time(NULL)) >> 2) & 0x0001FFFF;
|
||
|
|
||
|
m_dwStartId = (dwTTT << 13) | (1 << 12) | dwRRR;
|
||
|
m_dwLastId = m_dwStartId;
|
||
|
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
ErrInitCriticalSection( &m_csLock, hr );
|
||
|
if ( FAILED( hr ) )
|
||
|
return hr;
|
||
|
|
||
|
m_fInited = TRUE;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/*===================================================================
|
||
|
HRESULT CIdGenerator::Init(CIdGenerator StartId)
|
||
|
|
||
|
NOTE: Seed new starting Id with Id passed in
|
||
|
|
||
|
Parameters:
|
||
|
|
||
|
Returns: HRESULT (could fail to create critical section)
|
||
|
===================================================================*/
|
||
|
HRESULT CIdGenerator::Init(CIdGenerator & StartId)
|
||
|
{
|
||
|
Assert(!m_fInited);
|
||
|
|
||
|
m_dwStartId = StartId.m_dwStartId;
|
||
|
m_dwLastId = m_dwStartId;
|
||
|
|
||
|
HRESULT hr = NOERROR;
|
||
|
ErrInitCriticalSection( &m_csLock, hr );
|
||
|
if ( FAILED( hr ) )
|
||
|
return hr;
|
||
|
|
||
|
m_fInited = TRUE;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*===================================================================
|
||
|
DWORD CIdGenerator::NewId()
|
||
|
|
||
|
NOTE: Generates new ID
|
||
|
|
||
|
Parameters:
|
||
|
|
||
|
Returns: generated ID
|
||
|
===================================================================*/
|
||
|
DWORD CIdGenerator::NewId()
|
||
|
{
|
||
|
Assert(m_fInited);
|
||
|
|
||
|
DWORD dwId;
|
||
|
|
||
|
EnterCriticalSection(&m_csLock);
|
||
|
dwId = ++m_dwLastId;
|
||
|
LeaveCriticalSection(&m_csLock);
|
||
|
|
||
|
if (dwId == INVALID_ID)
|
||
|
{
|
||
|
// doesn't happen very often do critical section again
|
||
|
// to make the above critical section shorter
|
||
|
|
||
|
EnterCriticalSection(&m_csLock);
|
||
|
|
||
|
// check again in case other thread changed it
|
||
|
if (m_dwLastId == INVALID_ID)
|
||
|
m_dwLastId = m_dwStartId; // roll over
|
||
|
m_dwLastId++;
|
||
|
|
||
|
LeaveCriticalSection(&m_csLock);
|
||
|
|
||
|
dwId = m_dwLastId;
|
||
|
}
|
||
|
|
||
|
return dwId;
|
||
|
}
|
||
|
|
||
|
/*===================================================================
|
||
|
BOOL CIdGenerator::IsValidId(DWORD dwId)
|
||
|
|
||
|
NOTE: Checks if the given Id is valid (with start-last range)
|
||
|
|
||
|
Parameters:
|
||
|
DWORD dwId Id value to check
|
||
|
|
||
|
Returns: generated ID
|
||
|
===================================================================*/
|
||
|
BOOL CIdGenerator::IsValidId
|
||
|
(
|
||
|
DWORD dwId
|
||
|
)
|
||
|
{
|
||
|
Assert(m_fInited);
|
||
|
return (dwId > m_dwStartId && dwId <= m_dwLastId);
|
||
|
}
|