Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
4.6 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: ID Generator
  6. File: Idgener.cpp
  7. Owner: DmitryR
  8. This is the ID Generator source file.
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "Idgener.h"
  13. #include "memchk.h"
  14. /*===================================================================
  15. CIdGenerator::CIdGenerator
  16. NOTE: Constructor
  17. Parameters:
  18. Returns:
  19. ===================================================================*/
  20. CIdGenerator::CIdGenerator()
  21. : m_fInited(FALSE),
  22. m_dwStartId(0),
  23. m_dwLastId(0)
  24. {
  25. }
  26. /*===================================================================
  27. CIdGenerator::~CIdGenerator()
  28. NOTE: Destructor
  29. Parameters:
  30. Returns:
  31. ===================================================================*/
  32. CIdGenerator::~CIdGenerator()
  33. {
  34. if ( m_fInited )
  35. DeleteCriticalSection( &m_csLock );
  36. }
  37. /*===================================================================
  38. HRESULT CIdGenerator::Init()
  39. NOTE: Seed new starting Id
  40. Parameters:
  41. Returns: HRESULT (could fail to create critical section)
  42. ===================================================================*/
  43. HRESULT CIdGenerator::Init()
  44. {
  45. Assert(!m_fInited);
  46. /*===
  47. Seed the starting id
  48. The starting Id should be:
  49. 1) random
  50. 2) not to close to recently generated starting ids
  51. To accomplish the above, starting Id is in the
  52. following (binary) format:
  53. 00TT.TTTT TTTT.TTTT TTT1.RRRR RRRR.RRRR
  54. RRR is random number to introduce some
  55. randomness
  56. 1 is needed to make sure the id is far
  57. enough from 0
  58. TTT is current time() in 4 second increments.
  59. This means that 4 second in server restart
  60. delay translates into 8,192 difference in
  61. the starting Id (122880 sessions / minute).
  62. 17 bits of 4 sec intervals make a roll over
  63. time of about 145 hours, hopefully longer
  64. than a client's connection lifetime (not
  65. that it REALLY matters).
  66. 00 in the highest bits is to make sure it
  67. doesn't reach 0xffffffff too soon
  68. ===*/
  69. DWORD dwRRR = rand() & 0x00000FFF;
  70. DWORD dwTTT = (((DWORD)time(NULL)) >> 2) & 0x0001FFFF;
  71. m_dwStartId = (dwTTT << 13) | (1 << 12) | dwRRR;
  72. m_dwLastId = m_dwStartId;
  73. HRESULT hr = S_OK;
  74. ErrInitCriticalSection( &m_csLock, hr );
  75. if ( FAILED( hr ) )
  76. return hr;
  77. m_fInited = TRUE;
  78. return S_OK;
  79. }
  80. /*===================================================================
  81. HRESULT CIdGenerator::Init(CIdGenerator StartId)
  82. NOTE: Seed new starting Id with Id passed in
  83. Parameters:
  84. Returns: HRESULT (could fail to create critical section)
  85. ===================================================================*/
  86. HRESULT CIdGenerator::Init(CIdGenerator & StartId)
  87. {
  88. Assert(!m_fInited);
  89. m_dwStartId = StartId.m_dwStartId;
  90. m_dwLastId = m_dwStartId;
  91. HRESULT hr = NOERROR;
  92. ErrInitCriticalSection( &m_csLock, hr );
  93. if ( FAILED( hr ) )
  94. return hr;
  95. m_fInited = TRUE;
  96. return NOERROR;
  97. }
  98. /*===================================================================
  99. DWORD CIdGenerator::NewId()
  100. NOTE: Generates new ID
  101. Parameters:
  102. Returns: generated ID
  103. ===================================================================*/
  104. DWORD CIdGenerator::NewId()
  105. {
  106. Assert(m_fInited);
  107. DWORD dwId;
  108. EnterCriticalSection(&m_csLock);
  109. dwId = ++m_dwLastId;
  110. LeaveCriticalSection(&m_csLock);
  111. if (dwId == INVALID_ID)
  112. {
  113. // doesn't happen very often do critical section again
  114. // to make the above critical section shorter
  115. EnterCriticalSection(&m_csLock);
  116. // check again in case other thread changed it
  117. if (m_dwLastId == INVALID_ID)
  118. m_dwLastId = m_dwStartId; // roll over
  119. m_dwLastId++;
  120. LeaveCriticalSection(&m_csLock);
  121. dwId = m_dwLastId;
  122. }
  123. return dwId;
  124. }
  125. /*===================================================================
  126. BOOL CIdGenerator::IsValidId(DWORD dwId)
  127. NOTE: Checks if the given Id is valid (with start-last range)
  128. Parameters:
  129. DWORD dwId Id value to check
  130. Returns: generated ID
  131. ===================================================================*/
  132. BOOL CIdGenerator::IsValidId
  133. (
  134. DWORD dwId
  135. )
  136. {
  137. Assert(m_fInited);
  138. return (dwId > m_dwStartId && dwId <= m_dwLastId);
  139. }