Leaked source code of windows server 2003
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.

12426 lines
454 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. nmsdb.c
  5. Abstract:
  6. This module contains the functions used to interface with the
  7. database engine of choice. Currently that engine is the JetBlue
  8. engine
  9. Functions:
  10. NmsDbInit
  11. NmsDbInsertRowInd
  12. NmsDbInsertRowGrp
  13. NmsDbRelRow
  14. NmsDbQueryRow
  15. NmsDbUpdateRow
  16. NmsDbSeekNUpdateRow
  17. NmsDbGetDataRecs
  18. StoreGrpMems
  19. CreateTbl
  20. InitColInfo
  21. ReadOwnAddTbl
  22. NmsDbWriteOwnAddTbl
  23. NmsDbThdInit
  24. UpdateDb
  25. NmsDbUpdateVersNo
  26. NmsDbEndSession
  27. GetGrpMem
  28. NmsDbRelRes
  29. GetMaxVersNos
  30. InsertGrpMemsInCol
  31. NmsDbSetCurrentIndex
  32. NmsDbUpdNQueryIfMatch
  33. SetSystemParams
  34. Portability:
  35. This module is portable to different platforms.
  36. It is not portable across different engines
  37. Author:
  38. Pradeep Bahl (PradeepB) Dec-1992
  39. Revision History:
  40. Modification date Person Description of modification
  41. ----------------- ------- ----------------------------
  42. --*/
  43. /*
  44. Includes
  45. */
  46. #include <time.h>
  47. #include <stdio.h>
  48. #include <ctype.h>
  49. #include "wins.h"
  50. #include "nms.h"
  51. #include "nmsnmh.h"
  52. #include "winsthd.h" //
  53. #include "esent.h" //blue jet engine's header file
  54. #include "nmsdb.h" //
  55. #include "winsmsc.h" //
  56. #include "winscnf.h" //
  57. #include "winsevt.h" //
  58. #include "comm.h" //
  59. #include "rpl.h"
  60. #include "rplpull.h"
  61. #include "rplpush.h"
  62. #include "winsintf.h"
  63. #include "winswriter.hpp"
  64. #include "nmfilter.h"
  65. /*
  66. * Local Macro Declarations
  67. */
  68. #define NAMUSR "admin"
  69. #define PASSWD ""
  70. #define SYS_DB_PATH ".\\wins\\system.mdb"
  71. #define TEMP_DB_PATH ".\\wins\\winstmp.mdb"
  72. #define CHKPOINT_PATH ".\\wins"
  73. #define LOGFILE_PATH CHKPOINT_PATH
  74. // this constants are gone from the jet600 (ese.h) header file. But we still need
  75. // these constants for jet500/jet200 code path.
  76. #define JET_bitIndexClustered 0x00000010
  77. #define JET_bitCommitFlush 0x00000001 /* commit and flush page buffers. */
  78. #define INIT_NO_PAGES_IN_DB 1000 //initial size of database in pages
  79. #define MAX_FIXED_FLD_LEN 255 //maximum size of a fixed field
  80. #define PAD_FOR_REC_HEAP 1000 //pad to use when creating the
  81. //heap for getting records from
  82. //the db. This pad is to take
  83. //care of heap creation overhead
  84. // and for allocating memory for
  85. // group members.
  86. #define MAX_RECS_BEFORE_COMMIT 100 //max records to retrieve in
  87. //NmsDbGetDataRecs before doing a
  88. //commit
  89. //
  90. // Owner Id of the special record that stores the version number
  91. // of an owned record deleted or replaced with a replica
  92. //
  93. //
  94. // Don't want to wrap around to a negative number. Keep a pad of 16 just
  95. // for the heck of it.
  96. //
  97. #define OWNER_ID_OF_SPEC_REC 0x7FFFFFF0
  98. #define OWNER_ID_OF_SPEC_REC_OLD 250
  99. //
  100. // This determines the max. size (in bytes) of the buffer allocated the
  101. // first time a range of records need to retrived.
  102. //
  103. #define INIT_NO_OF_ENTRIES 1000
  104. #define NO_COLS_NAM_ADD_TBL 6 //no. of cols in Name Ip table
  105. #define NO_COLS_OWN_ADD_TBL 5 //no. of cols in Name Ip table
  106. //
  107. // Passed as third arg to JetCreateDatabase
  108. //
  109. #define CONNECT_INFO ";COUNTRY=1; LANGID=0x0409; CP=1252"
  110. //
  111. // Maximum number of sessions that can be active at any one time
  112. //
  113. // There can be a max of MAX_CNCRNT_STATIC_INITS (3 currently; check
  114. // winsintf.c) going on at any one time.
  115. //
  116. #define MAX_NO_SESSIONS (NMS_MAX_RPC_CALLS + WINSTHD_MAX_NO_NBT_THDS + \
  117. WINSTHD_NO_RPL_THDS + WINSTHD_NO_SCV_THDS +\
  118. WINSTHD_NO_CHL_THDS + WINSCNF_MAX_CNCRNT_STATIC_INITS )
  119. #pragma warning(4:4532) // Turn off return from __finally block warning until this code is cleaned
  120. // up to use __leave correctly.
  121. #define RET_M(JetRetStat) \
  122. { \
  123. DBGPRINT2(ERR, "Jet Error: JetRetStat is (%d). Line is (%d)\n", \
  124. (JetRetStat), __LINE__); \
  125. WINSEVT_LOG_M(JetRetStat, WINS_EVT_DATABASE_ERR); \
  126. return(WINS_FAILURE); \
  127. }
  128. #define CALL_M(fn) \
  129. { \
  130. JET_ERR _JetRetStat; \
  131. if ((_JetRetStat = (fn)) != JET_errSuccess) \
  132. { \
  133. RET_M(_JetRetStat); \
  134. } \
  135. }
  136. // this macro always requires JetRetStat local variable to receive the return value.
  137. #define CALL_N_JMP_M(fn, label) \
  138. { \
  139. if ((JetRetStat = (fn)) != JET_errSuccess) \
  140. { \
  141. DBGPRINT2(ERR, "Jet Error: JetRetStat is (%d). Line is (%d)\n", \
  142. (JetRetStat), __LINE__); \
  143. WINSEVT_LOG_M(JetRetStat, WINS_EVT_DATABASE_ERR); \
  144. goto label; \
  145. } \
  146. }
  147. #define CALL_N_RAISE_EXC_IF_ERR_M(fn) \
  148. { \
  149. JET_ERR _JetRetStat; \
  150. if ((_JetRetStat = (fn)) != JET_errSuccess) \
  151. { \
  152. DBGPRINT2(ERR, "Jet Error: _JetRetStat is (%d). Line is (%d)\n", \
  153. _JetRetStat, __LINE__); \
  154. WINSEVT_LOG_M(_JetRetStat, WINS_EVT_DATABASE_ERR); \
  155. WINS_RAISE_EXC_M(WINS_EXC_FAILURE); \
  156. } \
  157. }
  158. #if 0
  159. #define COMMIT_M(pSesId) \
  160. { \
  161. (JetRetStat) = JetCommitTransaction( \
  162. *pSesId, JET_bitCommitFlush); \
  163. if (JetRetStat != JET_errSuccess) \
  164. { \
  165. DBGPRINT1(ERR, "COMMIT FAILED: JetRetStat is (%d). \n", \
  166. (JetRetStat)); \
  167. WINSEVT_LOG_M((JetRetStat), WINS_EVT_COMMIT_ERR); \
  168. } \
  169. pTls->fTransActive = FALSE; \
  170. }
  171. #define ROLLBACK_M(pSesId) \
  172. { \
  173. WINS_TLS_T _pTls; \
  174. JET_SESID _SessId; \
  175. JET_ERR _JetRetStat; \
  176. if (pSesId == NULL) { GET_TLS_M(_pTls); ASSERT(_pTls != NULL)} \
  177. _JetRetStat = JetRollback( \
  178. _pTls->SesId, JET_bitRollbackAll));\
  179. if (_JetRetStat != JET_errSuccess) \
  180. { \
  181. DBGPRINT1(ERR, "ROllBACK FAILED: JetRetStat is (%d). \n", \
  182. _JetRetStat); \
  183. WINSEVT_LOG_M(_JetRetStat, WINS_EVT_ROLLBACK_ERR); \
  184. } \
  185. _pTls->fTransActive = FALSE; \
  186. }
  187. #endif
  188. #define JETRET_M(fn) \
  189. { \
  190. JET_ERR _JetRetStat; \
  191. if ((_JetRetStat = (fn)) != JET_errSuccess) \
  192. { \
  193. DBGPRINT2(ERR, "Jet Error: JetRetStat is (%d). Line is (%d)\n", \
  194. _JetRetStat, __LINE__); \
  195. WINSEVT_LOG_M(_JetRetStat, WINS_EVT_DATABASE_ERR); \
  196. return(_JetRetStat); \
  197. } \
  198. }
  199. /*
  200. * Local Typedef Declarations
  201. */
  202. /*
  203. FLD_T -- describes various attributes of a fld/col of a table
  204. */
  205. typedef struct _FLD_T {
  206. PBYTE pName; //name of field
  207. WORD FldTyp; //field type (unsigned byte, long, etc)
  208. BOOL fIndex; //Is it an index field
  209. BOOL fUnique;//Is the field value supposed to be unq
  210. PBYTE pIndex; //Index name
  211. PBYTE pb;
  212. DWORD Cb;
  213. DWORD Fid; //field id.
  214. } FLD_T, *PFLD_T;
  215. /*
  216. * Global Variable Definitions
  217. */
  218. /*
  219. NmsDbNoOfOwners -- This is the number of owners that are in the
  220. owner id to address mapping table. This variable is set
  221. by NmsDbInit (when it reads in the above table) and subsequently
  222. by the replicator
  223. This variable is protected by a critical section (not used at
  224. initialization time)
  225. */
  226. DWORD NmsDbNoOfOwners = 0; //No. of owners in the Nam - Add table
  227. /*
  228. NmsDbOwnAddTbl -- This is the in-memory table that stores the mappings
  229. between the owner id and the addresses.
  230. This table is initialized at init time with the database
  231. table NMSDB_OWN_ADD_TBL_NM if it exists.
  232. subsequently, more entries may be inserted into this
  233. table at replications as WINS learns of other WINS owners
  234. The insertions into this table are tagged at the end.
  235. In case of a configuration change, an entry may get
  236. flagged as DELETED, in which case it can be reused.
  237. This particular facet concering deletion is not
  238. operational currently
  239. This table is used by RPL_FIND_ADD_BY_OWNER_ID_M and
  240. by RplFindOwnrId
  241. */
  242. PNMSDB_ADD_STATE_T pNmsDbOwnAddTbl;
  243. DWORD NmsDbTotNoOfSlots = NMSDB_MAX_OWNERS_INITIALLY;
  244. CRITICAL_SECTION NmsDbOwnAddTblCrtSec;
  245. VERS_NO_T NmsDbStartVersNo;
  246. WINS_UID_T NmsDbUid;
  247. //
  248. // Must be initialized to 0. It is used by JetInit, JetBeginSession,
  249. // JetGetSystemParameter, JetSetSystemParameter, and JetTerm
  250. //
  251. // Only JetInit and JetSetSystemParameter take it by reference. Only
  252. // JetInit modifies it (Cheen Liao - 2/2/94).
  253. //
  254. JET_INSTANCE sJetInstance = 0;
  255. /*
  256. Name of the database file.
  257. This name will be read from the registry. For now, we are STATICally
  258. initializing the file name.
  259. */
  260. FUTURES("when jet is internationalized, use WINSCNF_DB_NAME")
  261. //BYTE NmsDbDatabaseFileName[WINS_MAX_FILENAME_SZ] = WINSCNF_DB_NAME_ASCII;
  262. //
  263. // STATICs for storing information about the special record that stores the
  264. // max. version number of an updated local record (one that got deleted or
  265. // replaced by a replica)
  266. //
  267. STATIC BOOL sfHighestVersNoRecExists = FALSE;
  268. //
  269. // Choose a name that is not likely to be used by any NBT client
  270. //
  271. STATIC LPBYTE spHighestVersNoRecNameOld = "xx--WINS--xx";
  272. STATIC LPBYTE spHighestVersNoRecName = "xx--WINS--xx--DHCP--xx--DNS--xx--GARBAGE1--1EGABRAG"; //more than a valid netbios name can store
  273. //
  274. // Stores the version number stored in the special record.
  275. //
  276. STATIC VERS_NO_T sHighestVersNoSaved;
  277. BOOL fConvJetDbCalled; //set to TRUE when the convert process has
  278. //been invoked. Checked in NmsDbInit
  279. BOOL fDbIs200; //set to TRUE when the convert process has
  280. //been invoked to convert 200 series db to latest format.
  281. //Checked in NmsDbInit.
  282. BOOL fDbIs500; //set to TRUE when the convert process has
  283. //been invoked to convert 500 series db to latest format.
  284. //Checked in NmsDbInit
  285. /*
  286. * Local Variable Definitions
  287. */
  288. /*
  289. Values indicating the type of index to be formed on a field.
  290. */
  291. #define CLUSTERED 0
  292. #define NOINDEX 1
  293. #define PRIMARYPART 2
  294. /*
  295. sNamAddTblRow
  296. Metadata about table that maps Names to IP addresses
  297. Note: The third and fourth fields are not used even though they are
  298. initialized.
  299. */
  300. STATIC FLD_T sNamAddTblRow[NO_COLS_NAM_ADD_TBL] =
  301. {
  302. { "name", JET_coltypBinary, CLUSTERED, TRUE, "dname" },
  303. { "address", JET_coltypLongBinary, NOINDEX, FALSE, NULL },
  304. { "flags", JET_coltypLong, NOINDEX, FALSE, NULL },
  305. #if NEW_OWID
  306. { "ownerid", JET_coltypLong, PRIMARYPART, TRUE, "ownerid"},
  307. #else
  308. { "ownerid", JET_coltypUnsignedByte, PRIMARYPART, TRUE, "ownerid"},
  309. #endif
  310. { "versionno", JET_coltypCurrency, PRIMARYPART, FALSE,"Version"},
  311. { "timestamp", JET_coltypLong, NOINDEX, FALSE, NULL }
  312. };
  313. /*
  314. The index of various fields in a row of Name -- Add table
  315. */
  316. #define NAM_ADD_NAME_INDEX 0
  317. #define NAM_ADD_ADDRESS_INDEX 1
  318. #define NAM_ADD_FLAGS_INDEX 2
  319. #define NAM_ADD_OWNERID_INDEX 3
  320. #define NAM_ADD_VERSIONNO_INDEX 4
  321. #define NAM_ADD_TIMESTAMP_INDEX 5
  322. /*
  323. sOwnAddTblRow
  324. Metadata about table that maps owner ids to addresses
  325. */
  326. STATIC FLD_T sOwnAddTblRow[NO_COLS_OWN_ADD_TBL] =
  327. {
  328. #if NEW_OWID
  329. { "OwnerId", JET_coltypLong, CLUSTERED, TRUE, "OwnerId" },
  330. #else
  331. { "OwnerId", JET_coltypUnsignedByte, CLUSTERED, TRUE, "OwnerId" },
  332. #endif
  333. { "address", JET_coltypBinary, NOINDEX, 0, "Address" },
  334. { "state", JET_coltypUnsignedByte, NOINDEX, 0, "State" },
  335. { "versionno", JET_coltypCurrency, NOINDEX, FALSE, "Version"},
  336. { "uid", JET_coltypLong, NOINDEX, FALSE, "Uid"}
  337. };
  338. #ifdef WINSDBG
  339. DWORD NmsDbDelDelDataRecs;
  340. DWORD NmsDbDelQueryNUpdRecs;
  341. #endif
  342. /*
  343. The index of various fields in a row of Owner Id -- Add table
  344. */
  345. #define OWN_ADD_OWNERID_INDEX 0
  346. #define OWN_ADD_ADDRESS_INDEX 1
  347. #define OWN_ADD_STATE_INDEX 2
  348. #define OWN_ADD_VERSIONNO_INDEX 3
  349. #define OWN_ADD_UID_INDEX 4
  350. #if DYNLOADJET
  351. DYN_LOAD_JET_VERSION DynLoadJetVersion = DYN_LOAD_JET_600;
  352. int NAM_ADD_OWNERID_SIZE;
  353. int OWN_ADD_OWNERID_SIZE;
  354. LPBYTE BASENAME;
  355. NMSDB_JETFTBL_T NmsDbJetFTbl[] = {
  356. #if _X86_
  357. Init,
  358. "JetInit@4", 145, NULL,
  359. Term,
  360. "JetTerm@4", 167, NULL,
  361. Term2,
  362. "JetTerm2@8", 167, NULL, //Jet200 does not have a JetTerm2
  363. SetSystemParameter,
  364. "JetSetSystemParameter@20", 165, NULL,
  365. BeginSession,
  366. "JetBeginSession@16", 104, NULL,
  367. EndSession,
  368. "JetEndSession@8", 124, NULL,
  369. CreateDatabase,
  370. "JetCreateDatabase@20", 112, NULL,
  371. AttachDatabase,
  372. "JetAttachDatabase@12", 102, NULL,
  373. DetachDatabase,
  374. "JetDetachDatabase@8", 121, NULL,
  375. CreateTable,
  376. "JetCreateTable@24", 115, NULL,
  377. DeleteTable,
  378. "JetDeleteTable@12", 120, NULL,
  379. GetTableColumnInfo,
  380. "JetGetTableColumnInfo@24", 137, NULL,
  381. GetColumnInfo,
  382. "JetGetColumnInfo@28", 127, NULL,
  383. AddColumn,
  384. "JetAddColumn@28", 101, NULL,
  385. CreateIndex,
  386. "JetCreateIndex@28", 113, NULL,
  387. BeginTransaction,
  388. "JetBeginTransaction@4", 105, NULL,
  389. CommitTransaction,
  390. "JetCommitTransaction@8", 109, NULL,
  391. Rollback,
  392. "JetRollback@8", 160, NULL,
  393. CloseDatabase,
  394. "JetCloseDatabase@12", 107, NULL,
  395. CloseTable,
  396. "JetCloseTable@8", 108, NULL,
  397. OpenDatabase,
  398. "JetOpenDatabase@20", 148, NULL,
  399. OpenTable,
  400. "JetOpenTable@28", 149, NULL,
  401. Delete,
  402. "JetDelete@8", 116, NULL,
  403. Update,
  404. "JetUpdate@20", 168, NULL,
  405. RetrieveColumn,
  406. "JetRetrieveColumn@32", 157, NULL,
  407. SetColumn,
  408. "JetSetColumn@28", 162, NULL,
  409. PrepareUpdate,
  410. "JetPrepareUpdate@12", 151, NULL,
  411. GetCurrentIndex,
  412. "JetGetCurrentIndex@16", 128, NULL,
  413. SetCurrentIndex,
  414. "JetSetCurrentIndex@12", 164, NULL,
  415. Move,
  416. "JetMove@16", 147, NULL,
  417. MakeKey,
  418. "JetMakeKey@20", 146, NULL,
  419. Seek,
  420. "JetSeek@12", 161, NULL,
  421. Backup,
  422. "JetBackup@12", 103, NULL,
  423. Restore,
  424. "JetRestore@8", 156, NULL
  425. #else
  426. Init,
  427. "JetInit", 145, NULL,
  428. Term,
  429. "JetTerm", 167, NULL,
  430. Term2,
  431. "JetTerm2", 167, NULL, //Jet200 does not have a JetTerm2
  432. SetSystemParameter,
  433. "JetSetSystemParameter", 165, NULL,
  434. BeginSession,
  435. "JetBeginSession", 104, NULL,
  436. EndSession,
  437. "JetEndSession", 124, NULL,
  438. CreateDatabase,
  439. "JetCreateDatabase", 112, NULL,
  440. AttachDatabase,
  441. "JetAttachDatabase", 102, NULL,
  442. DetachDatabase,
  443. "JetDetachDatabase", 121, NULL,
  444. CreateTable,
  445. "JetCreateTable", 115, NULL,
  446. DeleteTable,
  447. "JetDeleteTable", 120, NULL,
  448. GetTableColumnInfo,
  449. "JetGetTableColumnInfo", 137, NULL,
  450. GetColumnInfo,
  451. "JetGetColumnInfo", 127, NULL,
  452. AddColumn,
  453. "JetAddColumn", 101, NULL,
  454. CreateIndex,
  455. "JetCreateIndex", 113, NULL,
  456. BeginTransaction,
  457. "JetBeginTransaction", 105, NULL,
  458. CommitTransaction,
  459. "JetCommitTransaction", 109, NULL,
  460. Rollback,
  461. "JetRollback", 160, NULL,
  462. CloseDatabase,
  463. "JetCloseDatabase", 107, NULL,
  464. CloseTable,
  465. "JetCloseTable", 108, NULL,
  466. OpenDatabase,
  467. "JetOpenDatabase", 148, NULL,
  468. OpenTable,
  469. "JetOpenTable", 149, NULL,
  470. Delete,
  471. "JetDelete", 116, NULL,
  472. Update,
  473. "JetUpdate", 168, NULL,
  474. RetrieveColumn,
  475. "JetRetrieveColumn", 157, NULL,
  476. SetColumn,
  477. "JetSetColumn", 162, NULL,
  478. PrepareUpdate,
  479. "JetPrepareUpdate", 151, NULL,
  480. GetCurrentIndex,
  481. "JetGetCurrentIndex", 128, NULL,
  482. SetCurrentIndex,
  483. "JetSetCurrentIndex", 164, NULL,
  484. Move,
  485. "JetMove", 147, NULL,
  486. MakeKey,
  487. "JetMakeKey", 146, NULL,
  488. Seek,
  489. "JetSeek", 161, NULL,
  490. Backup,
  491. "JetBackup", 103, NULL,
  492. Restore,
  493. "JetRestore", 156, NULL
  494. #endif _X86_
  495. };
  496. #else
  497. #if NEW_OWID
  498. #define NAM_ADD_OWNERID_SIZE sizeof(DWORD)
  499. #else
  500. #define NAM_ADD_OWNERID_SIZE sizeof(BYTE)
  501. #endif
  502. #define OWN_ADD_OWNERID_SIZE NAM_ADD_OWNERID_SIZE
  503. #endif //DYNLOADJET
  504. /*
  505. * Local Function Prototype Declarations
  506. */
  507. /* prototypes for functions local to this module go here */
  508. STATIC
  509. STATUS
  510. CreateTbl(
  511. JET_DBID DbId,
  512. JET_SESID SesId,
  513. JET_TABLEID *pTblId,
  514. NMSDB_TBL_NAM_E TblNam_e //enumerator value for table to create
  515. );
  516. STATIC
  517. STATUS
  518. InitColInfo (
  519. JET_SESID SesId,
  520. JET_TABLEID TblId,
  521. NMSDB_TBL_NAM_E TblNam_e
  522. );
  523. STATIC
  524. STATUS
  525. ReadOwnAddTbl(
  526. JET_SESID SesId,
  527. JET_DBID DbId,
  528. JET_TABLEID TblId
  529. );
  530. STATIC
  531. JET_ERR
  532. UpdateDb (
  533. JET_SESID SesId,
  534. JET_TABLEID TblId,
  535. PNMSDB_ROW_INFO_T pRowInfo,
  536. ULONG TypOfUpd
  537. );
  538. STATIC
  539. STATUS
  540. GetGrpMem (
  541. IN JET_SESID SesId,
  542. IN JET_TABLEID TblId,
  543. IN PNMSDB_ROW_INFO_T pRowInfo,
  544. IN DWORD_PTR CurrentTime,
  545. IN OUT PNMSDB_STAT_INFO_T pStatInfo,
  546. // IN OUT PNMSDB_NODE_ADDS_T pNodeAdds,
  547. IN BOOL fIsStatic,
  548. OUT LPBOOL pfIsMem
  549. );
  550. STATIC
  551. STATUS
  552. GetMaxVersNos(
  553. JET_SESID SesId,
  554. JET_TABLEID TblId
  555. );
  556. STATIC
  557. __inline
  558. VOID
  559. StoreSpecVersNo(
  560. VOID
  561. );
  562. STATIC
  563. JET_ERR
  564. InsertGrpMemsInCol(
  565. JET_SESID SesId,
  566. JET_TABLEID TblId,
  567. PNMSDB_ROW_INFO_T pRowInfo,
  568. ULONG TypeOfUpd
  569. );
  570. STATIC
  571. VOID
  572. StoreGrpMems(
  573. IN PWINSTHD_TLS_T pTls,
  574. IN WINS_CLIENT_E WinsClient_e,
  575. IN LPBYTE pName,
  576. IN int ThdPrLvl,
  577. IN JET_SESID SesId,
  578. IN JET_TABLEID TblId,
  579. IN BOOL fIsStatic,
  580. OUT PRPL_REC_ENTRY_T pRspBuff
  581. );
  582. STATIC
  583. STATUS
  584. SetSystemParams(
  585. BOOL fBeforeInit
  586. );
  587. STATIC
  588. VOID
  589. UpdHighestVersNoRecIfReqd(
  590. IN PWINSTHD_TLS_T pTls,
  591. PNMSDB_ROW_INFO_T pRowInfo,
  592. PNMSDB_STAT_INFO_T pStatInfo
  593. );
  594. STATIC
  595. STATUS
  596. InitializeJetDb(
  597. PWINSTHD_TLS_T pTls,
  598. LPBOOL pfInitCallSucc,
  599. LPBOOL pfDatabaseOpened
  600. );
  601. STATIC
  602. STATUS
  603. AllocTls(
  604. LPVOID *ppTls
  605. );
  606. STATUS
  607. ObliterateWins(
  608. DWORD i,
  609. PCOMM_ADD_T pWinsAdd
  610. );
  611. #if DYNLOADJET
  612. STATUS
  613. SetForJet(
  614. VOID
  615. );
  616. #endif //DYNLOADJET
  617. STATUS
  618. ConvertJetDb(
  619. JET_ERR JetRetStat
  620. );
  621. /*
  622. function definitions start here
  623. */
  624. STATUS
  625. NmsDbInit(
  626. VOID
  627. )
  628. /*++
  629. Routine Description:
  630. This function initializes the database manager component of the Name
  631. Space Manager Component
  632. It does the following
  633. calls _tzset to init global variables used by time(). These
  634. global variables are set so that convertion of UST to local
  635. time is done (for instance when time() is called)by
  636. taking into account the timezone information.
  637. Initialize the database engine
  638. Start a session with the db engine
  639. Create and attach to a database file
  640. Create (and open) the name-address mapping table
  641. Create (and open) the owner-address mapping table
  642. create a clustered and primary index on the name-address table
  643. create a clustered index on the owner-address table
  644. Note: if the database already exists, it
  645. Attaches to it
  646. Opens the Name IP address Mapping table
  647. Arguments:
  648. None
  649. Externals Used:
  650. NmsDbOwnAddTblCrtSec
  651. Return Value:
  652. Success status codes --
  653. Error status codes --
  654. Error Handling:
  655. called by:
  656. main function of WINS
  657. Side Effects:
  658. Comments:
  659. None
  660. --*/
  661. {
  662. JET_ERR JetRetStat;
  663. PWINSTHD_TLS_T pTls;
  664. BOOL fFirstTime = TRUE;
  665. if (AllocTls(&pTls) != WINS_SUCCESS)
  666. {
  667. return(WINS_FAILURE);
  668. }
  669. _tzset(); /*
  670. func. uses TZ variable to assign values
  671. to three global variables used by time(). This is
  672. so that Universal Coordinated Time to may be
  673. adjusted to local time (timezone correction)
  674. */
  675. #if DYNLOADJET
  676. if (SetForJet() != WINS_SUCCESS)
  677. {
  678. return(WINS_FAILURE);
  679. }
  680. #endif
  681. //
  682. // Set Jet System params (ignore return status)
  683. //
  684. (VOID)SetSystemParams(TRUE);
  685. //
  686. // Initialize the critical section for protecting the in-memory
  687. //table NmsDbOwnAddTbl
  688. //
  689. // Note: This table is read and written to during stable state by
  690. // the Pull thread and the RPC threads executing WinsStatus()
  691. //
  692. // Check out RplFindOwnerId in rplpull.c
  693. //
  694. InitializeCriticalSection(&NmsDbOwnAddTblCrtSec);
  695. /*
  696. Initialize the Jet engine. This must be the first call
  697. unless JetSetSystemParameter is called to set system
  698. parameters. In that case, this call should be after that
  699. */
  700. while(TRUE)
  701. {
  702. BOOL fInitCallSucc;
  703. BOOL fDatabaseOpened;
  704. if (InitializeJetDb(pTls, &fInitCallSucc, &fDatabaseOpened) !=
  705. WINS_SUCCESS)
  706. {
  707. DWORD NoOfRestoresDone = 0;
  708. if (fFirstTime && !fDbIs200 && !fDbIs500)
  709. {
  710. //
  711. // If we have a backup path, attempt to do a restore
  712. //
  713. if (WinsCnf.pBackupDirPath != NULL)
  714. {
  715. DBGPRINT1(DET, "NmsDbInit: Doing Restore from path (%s)\n", WinsCnf.pBackupDirPath);
  716. //
  717. // If session is active, terminate it since we need
  718. // call JetInit again. That requires that first we
  719. // call JetTerm which does not expect any session to
  720. // be active
  721. //
  722. if (fNmsMainSessionActive)
  723. {
  724. //
  725. // Close tables opened in the session
  726. //
  727. NmsDbCloseTables();
  728. if (fDatabaseOpened)
  729. {
  730. CALL_M(JetCloseDatabase(
  731. pTls->SesId,
  732. pTls->DbId,
  733. 0 //find out what grbit can be
  734. //used
  735. )
  736. );
  737. }
  738. CALL_M(JetEndSession(
  739. pTls->SesId,
  740. 0
  741. )
  742. );
  743. fNmsMainSessionActive = FALSE;
  744. }
  745. //
  746. // if JetInit was successful, term jet activity
  747. //
  748. if (fInitCallSucc)
  749. {
  750. WinsWriterTerm();
  751. NmsDbRelRes();
  752. }
  753. //
  754. // We will try JetRestore a max of two times.
  755. //
  756. while(NoOfRestoresDone++ < 2)
  757. {
  758. if (DynLoadJetVersion >= DYN_LOAD_JET_500)
  759. {
  760. JetRetStat = JetRestore(WinsCnf.pBackupDirPath, NULL);
  761. }
  762. else
  763. {
  764. JetRetStat = JetRestore(WinsCnf.pBackupDirPath, 0, NULL, 0);
  765. }
  766. if (JetRetStat != JET_errSuccess)
  767. {
  768. if ( (
  769. (JetRetStat == JET_errBadLogVersion)
  770. ||
  771. (JetRetStat == JET_errBadLogSignature)
  772. ||
  773. (JetRetStat == JET_errInvalidLogSequence)
  774. ||
  775. (JetRetStat == JET_errExistingLogFileHasBadSignature)
  776. )
  777. &&
  778. (NoOfRestoresDone == 1)
  779. )
  780. {
  781. TCHAR LogFilePath[WINS_MAX_FILENAME_SZ];
  782. #define LOG_FILE_SUFFIX TEXT("*.log")
  783. WinsMscConvertAsciiStringToUnicode(
  784. WinsCnf.pLogFilePath, (LPBYTE)LogFilePath, sizeof(LogFilePath)/sizeof(TCHAR));
  785. //
  786. // Delete log files
  787. //
  788. WinsMscDelFiles(TRUE, LOG_FILE_SUFFIX, LogFilePath);
  789. continue;
  790. }
  791. WinsMscPutMsg(WINS_EVT_DB_RESTORE_GUIDE);
  792. CALL_M(JetRetStat);
  793. }
  794. WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_DB_RESTORED);
  795. break; // break out of while loop
  796. } // end of while()
  797. fFirstTime = FALSE;
  798. PERF("remove if not required")
  799. sJetInstance = 0; //defensive programming
  800. #if 0
  801. //
  802. // Start a session again
  803. //
  804. if (AllocTls(&pTls) != WINS_SUCCESS)
  805. {
  806. return(WINS_FAILURE);
  807. }
  808. //
  809. // Set Jet System params (ignore return status)
  810. //
  811. (VOID)SetSystemParams(TRUE);
  812. #endif
  813. continue;
  814. }
  815. WinsMscPutMsg(WINS_EVT_DB_RESTORE_GUIDE);
  816. //
  817. // There is no back up path specified in the registry. Return
  818. //
  819. return(WINS_FAILURE);
  820. }
  821. else
  822. {
  823. if (!fDbIs200 && !fDbIs500)
  824. {
  825. WinsMscPutMsg(WINS_EVT_DB_RESTORE_GUIDE);
  826. }
  827. else
  828. {
  829. //
  830. // If we are converting to NT 5.0, DynLoadJetVersion=DYN_LOAD_JET_600
  831. //
  832. if ( DynLoadJetVersion == DYN_LOAD_JET_600 ) {
  833. //
  834. // Put a pop-up and log an event based on which version
  835. // of Jet database we are converting from.
  836. //
  837. if (!fConvJetDbCalled)
  838. {
  839. WINSEVT_LOG_INFO_D_M(
  840. WINS_SUCCESS,
  841. fDbIs200 ? WINS_EVT_DB_CONV_351_TO_5_GUIDE
  842. : WINS_EVT_DB_CONV_4_TO_5_GUIDE);
  843. // As per bug#339015 remove popups
  844. // WinsMscPutMsg(
  845. // fDbIs200 ? WINS_EVT_DB_CONV_351_TO_5_GUIDE
  846. // : WINS_EVT_DB_CONV_4_TO_5_GUIDE);
  847. }
  848. else
  849. {
  850. //WinsMscPutMsg(WINS_EVT_TEMP_TERM_UNTIL_CONV_TO_5);
  851. }
  852. }
  853. //
  854. // If we are converting to NT 4.0, DynLoadJetVersion=DYN_LOAD_JET_500
  855. //
  856. else if(DynLoadJetVersion == DYN_LOAD_JET_500) {
  857. if (!fConvJetDbCalled)
  858. {
  859. WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_DB_CONV_GUIDE);
  860. WinsMscPutMsg(WINS_EVT_DB_CONV_GUIDE);
  861. }
  862. else
  863. {
  864. WinsMscPutMsg(WINS_EVT_TEMP_TERM_UNTIL_CONV);
  865. }
  866. }else {
  867. //
  868. // We should never come here.
  869. //
  870. ASSERT(FALSE);
  871. }
  872. }
  873. //
  874. // We got an error a second time. Return
  875. //
  876. return(WINS_FAILURE);
  877. }
  878. }
  879. break; //break out of the while loop
  880. } // end of while(TRUE)
  881. //
  882. // Init Push records if required
  883. //
  884. RPLPUSH_INIT_PUSH_RECS_M(&WinsCnf);
  885. NMSNMH_DEC_VERS_NO_M(NmsNmhMyMaxVersNo, NmsDbStartVersNo);
  886. //
  887. // Set our UID to be the time when the db got initialized
  888. //
  889. {
  890. time_t timeNow;
  891. (void)time(&timeNow);
  892. NmsDbUid = (DWORD)timeNow;
  893. }
  894. return(WINS_SUCCESS);
  895. }
  896. STATUS
  897. AllocTls(
  898. LPVOID *ppTls
  899. )
  900. /*++
  901. Routine Description:
  902. This function is called to allocate TLS
  903. Arguments:
  904. Externals Used:
  905. None
  906. Return Value:
  907. Success status codes --
  908. Error status codes --
  909. Error Handling:
  910. Called by:
  911. NmsDbInit
  912. Side Effects:
  913. Comments:
  914. --*/
  915. {
  916. PWINSTHD_TLS_T pTls;
  917. WinsMscAlloc( sizeof(WINSTHD_TLS_T), ppTls);
  918. pTls = *ppTls;
  919. pTls->fNamAddTblOpen = FALSE;
  920. pTls->fOwnAddTblOpen = FALSE;
  921. /*
  922. * Let us store the address in the TLS storage
  923. */
  924. if (!TlsSetValue(WinsTlsIndex, pTls))
  925. {
  926. DWORD Error;
  927. Error = GetLastError();
  928. DBGPRINT1(ERR, "NmsDbAllocTlc: TlsSetValue returned error. Error = (%d)\n", Error);
  929. WINSEVT_LOG_M(Error, WINS_EVT_CANT_INIT);
  930. return(WINS_FAILURE);
  931. }
  932. return(WINS_SUCCESS);
  933. }
  934. STATUS
  935. InitializeJetDb(
  936. PWINSTHD_TLS_T pTls,
  937. LPBOOL pfInitCallSucc,
  938. LPBOOL pfDatabaseOpened
  939. )
  940. /*++
  941. Routine Description:
  942. This function opens the Jet db and tables
  943. Arguments:
  944. Externals Used:
  945. None
  946. Return Value:
  947. Success status codes -- WINS_SUCCESS
  948. Error status codes -- WINS_FAILURE
  949. Error Handling:
  950. Called by:
  951. Side Effects:
  952. Comments:
  953. None
  954. --*/
  955. {
  956. JET_ERR JetRetStat;
  957. JET_SESID SesId;
  958. JET_DBID DbId;
  959. BOOL fOwnAddTblCreated = FALSE; /*indicates whether the
  960. owner id to address
  961. mapping table was created
  962. at init time
  963. */
  964. *pfDatabaseOpened = FALSE;
  965. JetRetStat = JetInit(&sJetInstance);
  966. DBGPRINT1(ERR, "JetInit returning (%d)\n", (JetRetStat));
  967. if (JetRetStat != JET_errSuccess)
  968. {
  969. *pfInitCallSucc = FALSE;
  970. if ((JetRetStat == JET_errDatabase200Format) || (JetRetStat == JET_errDatabase500Format))
  971. {
  972. ConvertJetDb(JetRetStat);
  973. }
  974. else
  975. {
  976. //
  977. // We could have got an error because the LogFilePath
  978. // is messed up in the registry. We try again, this time using
  979. // the default log file path.
  980. //
  981. // Most of the time, we get FileNotFound error. We have seen
  982. // "bad signature" error once. Let us just do this for all
  983. // errors. The situation will not be any worse than before if
  984. // JetInit fails again.
  985. //
  986. // Set the default log path
  987. //
  988. SetSystemParams(FALSE);
  989. JetRetStat = JetInit(&sJetInstance);
  990. }
  991. CALL_M(JetRetStat);
  992. }
  993. WinsWriterInit();
  994. *pfInitCallSucc = TRUE;
  995. /*
  996. Start a session.
  997. */
  998. CALL_M( JetBeginSession(
  999. sJetInstance,
  1000. &pTls->SesId,
  1001. NAMUSR,
  1002. PASSWD )
  1003. );
  1004. fNmsMainSessionActive = TRUE;
  1005. SesId = pTls->SesId;
  1006. //
  1007. // Create/Open the database
  1008. //
  1009. if ((JetRetStat = JetCreateDatabase(
  1010. SesId,
  1011. // NmsDbDatabaseFileName,
  1012. WinsCnf.pWinsDb,
  1013. CONNECT_INFO,
  1014. &pTls->DbId,
  1015. 0 //grbit; Don't want exclusive use
  1016. )) == JET_errDatabaseDuplicate
  1017. )
  1018. {
  1019. //
  1020. // let us attach to the database. This is required for
  1021. // opening databases that were created in a different
  1022. // directory (Ian -- 11/23/93). We will get a warning
  1023. // if the database was created in this very directory
  1024. //
  1025. JetRetStat = JetAttachDatabase( SesId, WinsCnf.pWinsDb/*NmsDbDatabaseFileName*/, 0 );
  1026. if (
  1027. (JetRetStat != JET_wrnDatabaseAttached)
  1028. &&
  1029. (JetRetStat != JET_errSuccess)
  1030. )
  1031. {
  1032. if ((JetRetStat == JET_errDatabase200Format) || (JetRetStat == JET_errDatabase500Format))
  1033. {
  1034. //
  1035. // Start the convert process
  1036. //
  1037. JetRetStat = ConvertJetDb(JetRetStat);
  1038. *pfInitCallSucc = TRUE;
  1039. }
  1040. CALL_M(JetRetStat);
  1041. }
  1042. //
  1043. // If JetRetStat is success, it means ...
  1044. //
  1045. // The new db path is different from the old one. We need
  1046. // to detach so that Jet forgets about the old one. We then
  1047. // attach to the new one again
  1048. //
  1049. if (JetRetStat == JET_errSuccess)
  1050. {
  1051. CALL_M(JetDetachDatabase(SesId, NULL));
  1052. CALL_M(JetAttachDatabase(SesId, WinsCnf.pWinsDb, 0 ));
  1053. }
  1054. CALL_M(JetOpenDatabase(
  1055. SesId,
  1056. //NmsDbDatabaseFileName,
  1057. WinsCnf.pWinsDb,
  1058. NULL, /*the default engine*/
  1059. &pTls->DbId,
  1060. 0
  1061. )
  1062. );
  1063. *pfDatabaseOpened = TRUE;
  1064. DbId = pTls->DbId;
  1065. JetRetStat = JetOpenTable(
  1066. SesId,
  1067. DbId,
  1068. NMSDB_NAM_ADD_TBL_NM,
  1069. NULL, /*ptr to parameter list; should be
  1070. *non-NULL if a query is being
  1071. *opened*/
  1072. 0, /*Length of above parameter list*/
  1073. 0, //shared access (no bit set)
  1074. &pTls->NamAddTblId
  1075. );
  1076. //
  1077. // If the name-address mapping table was not found, create it
  1078. //
  1079. if (JetRetStat == JET_errObjectNotFound)
  1080. {
  1081. DBGPRINT0(INIT, "InitializeJetDb:Creating Name-Address table\n");
  1082. CALL_M(CreateTbl(
  1083. DbId,
  1084. SesId,
  1085. &pTls->NamAddTblId,
  1086. NMSDB_E_NAM_ADD_TBL_NM
  1087. )
  1088. );
  1089. //
  1090. // Set this so that we close the table when we end the
  1091. // session
  1092. //
  1093. pTls->fNamAddTblOpen = TRUE;
  1094. }
  1095. else
  1096. {
  1097. CALL_M(JetRetStat);
  1098. pTls->fNamAddTblOpen = TRUE;
  1099. //
  1100. // get and store in in-memory data structure, the
  1101. // information about the columns of the name-address
  1102. // mapping table
  1103. //
  1104. CALL_M(InitColInfo(
  1105. SesId,
  1106. pTls->NamAddTblId,
  1107. NMSDB_E_NAM_ADD_TBL_NM
  1108. ));
  1109. //
  1110. // get the max. version numbers of records owned
  1111. // by different owners. These will be stored in
  1112. // the RplPullOwnerVersNo table
  1113. //
  1114. CALL_M(GetMaxVersNos(
  1115. SesId,
  1116. pTls->NamAddTblId
  1117. ));
  1118. }
  1119. //
  1120. // Open the owner-address mapping table
  1121. //
  1122. JetRetStat = JetOpenTable(
  1123. SesId,
  1124. DbId,
  1125. NMSDB_OWN_ADD_TBL_NM,
  1126. NULL, /*ptr to parameter list; should be
  1127. *non-NULL if a query is being
  1128. *opened*/
  1129. 0, /*Length of above parameter list*/
  1130. 0, //shared access (no bit set)
  1131. &pTls->OwnAddTblId
  1132. );
  1133. if (JetRetStat == JET_errObjectNotFound)
  1134. {
  1135. DBGPRINT0(INIT, "InitializeJetDb:Creating Owner-Address table\n");
  1136. //
  1137. // Create the ownerid-address mapping table
  1138. //
  1139. CALL_M(CreateTbl(
  1140. DbId,
  1141. SesId,
  1142. &pTls->OwnAddTblId,
  1143. NMSDB_E_OWN_ADD_TBL_NM
  1144. )
  1145. );
  1146. //
  1147. // Set this so that we close the table when we
  1148. // end the session
  1149. //
  1150. pTls->fOwnAddTblOpen = TRUE;
  1151. fOwnAddTblCreated = TRUE;
  1152. }
  1153. else
  1154. {
  1155. pTls->fOwnAddTblOpen = TRUE;
  1156. CALL_M(InitColInfo(
  1157. SesId,
  1158. pTls->OwnAddTblId,
  1159. NMSDB_E_OWN_ADD_TBL_NM
  1160. )
  1161. );
  1162. }
  1163. }
  1164. else //if database file was not existent and has now been created
  1165. {
  1166. if (JetRetStat == JET_errSuccess)
  1167. {
  1168. DBGPRINT0(INIT, "InitializeJetDb: Database file was not there. It has been created\n");
  1169. *pfDatabaseOpened = TRUE;
  1170. DbId = pTls->DbId;
  1171. //
  1172. // Create the name -address mapping table
  1173. //
  1174. CALL_M(CreateTbl(
  1175. DbId,
  1176. SesId,
  1177. &pTls->NamAddTblId,
  1178. NMSDB_E_NAM_ADD_TBL_NM
  1179. )
  1180. );
  1181. pTls->fNamAddTblOpen = TRUE;
  1182. //
  1183. // Create the ownerid-address mapping table
  1184. //
  1185. CALL_M(CreateTbl(
  1186. DbId,
  1187. SesId,
  1188. &pTls->OwnAddTblId,
  1189. NMSDB_E_OWN_ADD_TBL_NM
  1190. )
  1191. );
  1192. pTls->fOwnAddTblOpen = TRUE;
  1193. fOwnAddTblCreated = TRUE;
  1194. }
  1195. else
  1196. {
  1197. *pfDatabaseOpened = FALSE;
  1198. RET_M(JetRetStat);
  1199. }
  1200. }
  1201. //
  1202. // Allocate the NmsDbOwnAddTbl table in memory
  1203. //
  1204. WinsMscAlloc(
  1205. sizeof(NMSDB_ADD_STATE_T) * NmsDbTotNoOfSlots,
  1206. &pNmsDbOwnAddTbl
  1207. );
  1208. /*
  1209. If the Owner - Address table was there, read its contents into
  1210. an in-memory table
  1211. */
  1212. FUTURES("Pass ptr to an in-memory table instead of having ReadOwnAddTbl")
  1213. FUTURES("assume that one is present")
  1214. if (!fOwnAddTblCreated)
  1215. {
  1216. ReadOwnAddTbl(
  1217. SesId,
  1218. DbId,
  1219. pTls->OwnAddTblId
  1220. );
  1221. }
  1222. //
  1223. // Set the current index on the name-address table to the
  1224. // clustered index
  1225. //
  1226. CALL_M(
  1227. JetSetCurrentIndex( SesId,
  1228. pTls->NamAddTblId,
  1229. NMSDB_NAM_ADD_CLUST_INDEX_NAME
  1230. )
  1231. );
  1232. return(WINS_SUCCESS);
  1233. } // end InitialiazeJetDb
  1234. STATUS
  1235. NmsDbInsertRowInd(
  1236. PNMSDB_ROW_INFO_T pRowInfo,
  1237. PNMSDB_STAT_INFO_T pStatusInfo
  1238. )
  1239. /*++
  1240. Routine Description:
  1241. This function inserts a unique name-IP address mapping row in the
  1242. name-IP address mapping table. In case of a conflict, it returns
  1243. an error status and information about the conflicting
  1244. record that includes
  1245. Status -- group/unique
  1246. IP address(es) of the conflicting record (one address if
  1247. it was a unique record, one or more if it was
  1248. a special group).
  1249. state -- the state of the record (active/released/tombstone)
  1250. Arguments:
  1251. pRowInfo - Info. about the row to insert
  1252. pStatusInfo - Contains status of the operation + info about the
  1253. conflicting record, if the registration conflicted
  1254. with an entry in the db.
  1255. Externals Used:
  1256. None
  1257. Return Value:
  1258. Success status codes -- WINS_SUCCESS
  1259. Error status codes -- WINS_FAILURE
  1260. Error Handling:
  1261. Called by:
  1262. NmsNmhNamRegInd
  1263. Side Effects:
  1264. Comments:
  1265. None
  1266. --*/
  1267. {
  1268. DWORD FldNo = 0;
  1269. JET_ERR JetRetStat;
  1270. DWORD FlagVal = 0; //flag value of record
  1271. DWORD ActFldLen = 0; //length of fld retrieved
  1272. JET_TABLEID TblId;
  1273. JET_SESID SesId;
  1274. PWINSTHD_TLS_T pTls;
  1275. BOOL fWaitDone = FALSE;
  1276. GET_TLS_M(pTls);
  1277. ASSERT(pTls != NULL);
  1278. TblId = pTls->NamAddTblId;
  1279. SesId = pTls->SesId;
  1280. pStatusInfo->StatCode = NMSDB_SUCCESS;
  1281. JetRetStat = UpdateDb(
  1282. SesId,
  1283. TblId,
  1284. pRowInfo,
  1285. JET_prepInsert
  1286. );
  1287. if ( JetRetStat == JET_errKeyDuplicate )
  1288. {
  1289. pStatusInfo->StatCode = NMSDB_CONFLICT;
  1290. /*
  1291. * retrieve the conflicting record's
  1292. * flag byte.
  1293. */
  1294. CALL_M( JetMakeKey(
  1295. SesId,
  1296. TblId,
  1297. pRowInfo->pName,
  1298. pRowInfo->NameLen,
  1299. JET_bitNewKey
  1300. )
  1301. );
  1302. if ((JetRetStat = JetSeek(
  1303. SesId,
  1304. TblId,
  1305. JET_bitSeekEQ
  1306. )) == JET_errSuccess
  1307. )
  1308. {
  1309. // retrieve the flags column
  1310. CALL_M( JetRetrieveColumn(
  1311. SesId,
  1312. TblId,
  1313. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  1314. &FlagVal,
  1315. sizeof(FlagVal),
  1316. &ActFldLen,
  1317. 0,
  1318. NULL
  1319. )
  1320. );
  1321. pStatusInfo->EntTyp = (BYTE)NMSDB_ENTRY_TYPE_M(FlagVal);
  1322. pStatusInfo->fStatic = NMSDB_IS_ENTRY_STATIC_M(FlagVal);
  1323. pStatusInfo->EntryState_e =
  1324. NMSDB_ENTRY_STATE_M(FlagVal);
  1325. if (NMSDB_ENTRY_UNIQUE_M(pStatusInfo->EntTyp))
  1326. {
  1327. FUTURES("Remove this RETINFO thing. Presumably, it is not needed")
  1328. /* It is a unique entry*/
  1329. JET_RETINFO RetInfo;
  1330. RetInfo.itagSequence = 1;
  1331. RetInfo.cbStruct = sizeof(JET_RETINFO);
  1332. RetInfo.ibLongValue = 0;
  1333. // retrieve the ip address column
  1334. CALL_M(
  1335. JetRetrieveColumn(
  1336. SesId,
  1337. TblId,
  1338. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  1339. &(pStatusInfo->NodeAdds.Mem[0].Add),
  1340. sizeof(COMM_ADD_T),
  1341. &ActFldLen,
  1342. 0,
  1343. &RetInfo
  1344. )
  1345. );
  1346. pStatusInfo->NodeAdds.NoOfMems = 1;
  1347. }
  1348. else
  1349. {
  1350. if (NMSDB_ENTRY_MULTIHOMED_M(pStatusInfo->EntTyp))
  1351. {
  1352. //
  1353. // If status is active, we get the
  1354. // group members
  1355. //
  1356. if (pStatusInfo->EntryState_e ==
  1357. NMSDB_E_ACTIVE)
  1358. {
  1359. BOOL fIsMem;
  1360. #if 0
  1361. //NOTE: No need to do the following, since we don't care about the value of
  1362. //fIsMem returned GetGrpMem()
  1363. pRowInfo->NodeAdds.NoOfMems = 1;
  1364. pRowInfo->NodeAdds.Mem[0].Add =
  1365. *(pRowInfo->pNodeAdd);
  1366. #endif
  1367. PERF("If entry in conflict is STATIC, we don't need to get grp members")
  1368. PERF("except maybe for multihomed entries. Checkout Clash functions (nmsnmh.c)")
  1369. if (GetGrpMem(
  1370. SesId,
  1371. TblId,
  1372. pRowInfo,
  1373. pRowInfo->TimeStamp - ((pRowInfo->OwnerId == NMSDB_LOCAL_OWNER_ID) ? WinsCnf.RefreshInterval : WinsCnf.VerifyInterval) ,
  1374. pStatusInfo,
  1375. pStatusInfo->fStatic,
  1376. &fIsMem
  1377. ) != WINS_SUCCESS)
  1378. {
  1379. return(WINS_FAILURE);
  1380. }
  1381. //
  1382. // If all members are expired, then
  1383. // mark entry in conflict as a
  1384. // TOMBSTONE (for the benefit of
  1385. // ClashAtRegInd and ClashAtReplUniqueR)
  1386. //
  1387. if (pStatusInfo->NodeAdds.NoOfMems == 0)
  1388. {
  1389. pStatusInfo->EntryState_e =
  1390. NMSDB_E_RELEASED;
  1391. }
  1392. }
  1393. else
  1394. {
  1395. pStatusInfo->NodeAdds.NoOfMems = 0;
  1396. }
  1397. }
  1398. }
  1399. #if !NEW_OWID
  1400. pStatusInfo->OwnerId = 0;
  1401. #endif
  1402. /*
  1403. * Retrieve the owner Id column.
  1404. */
  1405. CALL_M(
  1406. JetRetrieveColumn(
  1407. SesId,
  1408. TblId,
  1409. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  1410. &pStatusInfo->OwnerId,
  1411. NAM_ADD_OWNERID_SIZE,
  1412. &ActFldLen,
  1413. 0,
  1414. NULL
  1415. )
  1416. );
  1417. //
  1418. // Just in case we challenge this entry and it
  1419. // happens to be multihomed, we would need to add
  1420. // it as a member (see ProcAddList).
  1421. //
  1422. if (NMSDB_ENTRY_UNIQUE_M(pStatusInfo->EntTyp))
  1423. {
  1424. pStatusInfo->NodeAdds.Mem[0].OwnerId =
  1425. pStatusInfo->OwnerId;
  1426. //
  1427. // Put the current time stamp as the time
  1428. // stamp of the member. Though not strictly
  1429. // correct, it is ok. We don't
  1430. // need to retrieve the time stamp of the
  1431. // conflicting record this way.
  1432. //
  1433. if (pStatusInfo->OwnerId ==
  1434. NMSDB_LOCAL_OWNER_ID)
  1435. {
  1436. pStatusInfo->NodeAdds.Mem[0].TimeStamp
  1437. = pRowInfo->TimeStamp;
  1438. }
  1439. }
  1440. //
  1441. // If the conflicting record is owned by the local
  1442. // WINS, we must retrieve the version number. This
  1443. // is used to determine whether the special record
  1444. // storing the highest version number of the
  1445. // local records should be updated (refer:
  1446. // NmsDbUpdateRow, NmsDbSeekNUpd, NmsScvDoScavenging,
  1447. // NmsDbUpdHighestVersNoRec)
  1448. //
  1449. if (pStatusInfo->OwnerId == NMSDB_LOCAL_OWNER_ID)
  1450. {
  1451. //
  1452. // Retrieve the version number
  1453. //
  1454. CALL_M( JetRetrieveColumn(
  1455. SesId,
  1456. TblId,
  1457. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  1458. &(pStatusInfo->VersNo),
  1459. sizeof(VERS_NO_T),
  1460. &ActFldLen,
  1461. 0,
  1462. NULL
  1463. )
  1464. );
  1465. }
  1466. }
  1467. else //could not seek to the record
  1468. {
  1469. #if 0
  1470. // use the following code only if there is a thread somewhere in WINS that
  1471. // updates the db without first entering the NmsNmhNamRegCrtSec critical
  1472. // section.
  1473. //
  1474. // For registration done by RPLPULL thread where the version number is not
  1475. // incremented, we do not have to enter the above critical section. Currently
  1476. // we do enter it. If in the future we stop doing so, we will uncomment the
  1477. // following code.
  1478. //
  1479. if (!fWaitDone)
  1480. {
  1481. WINSEVT_LOG_INFO_M(
  1482. WINS_SUCCESS,
  1483. WINS_EVT_CANT_FIND_REC
  1484. );
  1485. Sleep(10); //sleep for 10 msecs to let the other
  1486. //thread commit/rollback the transaction
  1487. //that is inserting a record that caused
  1488. //the conflict
  1489. //
  1490. // Set flag to TRUE so that if we get the same
  1491. // error again, we can log an error and raise
  1492. // an exception
  1493. //
  1494. fWaitDone = TRUE;
  1495. continue; //iterate one more time
  1496. }
  1497. #endif
  1498. /*
  1499. * We should never get here. Something major is wrong
  1500. * (probably with Jet)
  1501. */
  1502. DBGPRINT1(EXC, "NmsDbInsertRowInd: Could not seek to conflicting record. WEIRD. Error is (%d)\n", JetRetStat);
  1503. WINSEVT_LOG_M(JetRetStat, WINS_EVT_F_CANT_FIND_REC);
  1504. ASSERTMSG(0, "SEEK ERROR");
  1505. WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
  1506. } // end of else
  1507. } //no duplicate
  1508. CALL_M(JetRetStat);
  1509. return(WINS_SUCCESS);
  1510. }
  1511. STATUS
  1512. NmsDbInsertRowGrp(
  1513. PNMSDB_ROW_INFO_T pRowInfo,
  1514. PNMSDB_STAT_INFO_T pStatusInfo
  1515. )
  1516. /*++
  1517. Routine Description:
  1518. This function inserts a group name-IP address mapping row in the
  1519. name-IP address mapping table. It first seeks on the name to see
  1520. if there is an entry with that name. if yes, it retrieves the
  1521. information about the conflicting record for the benefit of the
  1522. calling function and returns.
  1523. Information retrieved includes
  1524. Status -- group/unique
  1525. IP addresses pertaining to the entry
  1526. state -- the state of the record (active/released/tombstone)
  1527. Arguments:
  1528. pRowInfo - Info. about the row to insert
  1529. pStatusInfo - Contains status of the operation + info about the
  1530. conflicting record, if the registration conflicted
  1531. with an entry in the db.
  1532. Externals Used:
  1533. None
  1534. Return Value:
  1535. Success status codes -- WINS_SUCCESS
  1536. Error status codes -- WINS_FAILURE
  1537. Error Handling:
  1538. Called by:
  1539. NmsNmhNamRegGrp
  1540. Side Effects:
  1541. Comments:
  1542. None
  1543. --*/
  1544. {
  1545. DWORD FldNo = 0;
  1546. JET_ERR JetRetStat;
  1547. DWORD FlagVal = 0; //flag value of record that is
  1548. //retrieved
  1549. DWORD ActFldLen = 0; //length of fld retrieved
  1550. BOOL fFound = FALSE; //set to TRUE if Address is found in
  1551. //group
  1552. BOOL fWaitDone = FALSE;
  1553. JET_RETINFO RetInfo;
  1554. JET_SESID SesId;
  1555. JET_TABLEID TblId;
  1556. PWINSTHD_TLS_T pTls;
  1557. GET_TLS_M(pTls);
  1558. ASSERT(pTls != NULL);
  1559. TblId = pTls->NamAddTblId;
  1560. SesId = pTls->SesId;
  1561. pStatusInfo->StatCode = NMSDB_SUCCESS;
  1562. //
  1563. // So that we repeat the whole while loop in case we are not
  1564. // able to seek after a conflict
  1565. //
  1566. JetRetStat = UpdateDb(
  1567. SesId,
  1568. TblId,
  1569. pRowInfo,
  1570. JET_prepInsert
  1571. );
  1572. if ( JetRetStat == JET_errKeyDuplicate )
  1573. {
  1574. pStatusInfo->StatCode = NMSDB_CONFLICT;
  1575. CALL_M( JetMakeKey(
  1576. SesId,
  1577. TblId,
  1578. pRowInfo->pName,
  1579. pRowInfo->NameLen,
  1580. JET_bitNewKey
  1581. )
  1582. );
  1583. if ((JetRetStat = JetSeek(
  1584. SesId,
  1585. TblId,
  1586. JET_bitSeekEQ
  1587. )) == JET_errSuccess
  1588. )
  1589. {
  1590. // retrieve the flags column
  1591. CALL_M( JetRetrieveColumn(
  1592. SesId,
  1593. TblId,
  1594. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  1595. &FlagVal,
  1596. sizeof(FlagVal),
  1597. &ActFldLen,
  1598. 0,
  1599. NULL
  1600. )
  1601. );
  1602. pStatusInfo->EntryState_e =
  1603. NMSDB_ENTRY_STATE_M(FlagVal);
  1604. pStatusInfo->EntTyp =
  1605. (BYTE)NMSDB_ENTRY_TYPE_M(FlagVal);
  1606. pStatusInfo->fStatic =
  1607. NMSDB_IS_ENTRY_STATIC_M(FlagVal);
  1608. if (pStatusInfo->EntTyp == NMSDB_UNIQUE_ENTRY)
  1609. {
  1610. /* It is a unique entry*/
  1611. FUTURES("Remove this RETINFO thing. Presumably, it is not needed")
  1612. /* It is a unique entry*/
  1613. RetInfo.itagSequence = 1;
  1614. RetInfo.cbStruct = sizeof(JET_RETINFO);
  1615. RetInfo.ibLongValue = 0;
  1616. // retrieve the ip address column
  1617. CALL_M(
  1618. JetRetrieveColumn(
  1619. SesId,
  1620. TblId,
  1621. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  1622. &(pStatusInfo->NodeAdds.Mem[0].Add),
  1623. sizeof(COMM_ADD_T),
  1624. &ActFldLen,
  1625. 0,
  1626. &RetInfo
  1627. )
  1628. );
  1629. pStatusInfo->NodeAdds.NoOfMems = 1;
  1630. }
  1631. else //it is a group entry or a multihomed entry
  1632. {
  1633. if (pStatusInfo->EntTyp != NMSDB_NORM_GRP_ENTRY)
  1634. {
  1635. //
  1636. // If status is active, we get the
  1637. // group members
  1638. //
  1639. if (pStatusInfo->EntryState_e ==
  1640. NMSDB_E_ACTIVE)
  1641. {
  1642. BOOL fIsMem;
  1643. PERF("If entry in conflict is STATIC, we don't need to get grp members")
  1644. PERF("except maybe for multihomed entries. Checkout Clash functions (nmsnmh.c)")
  1645. if (GetGrpMem(
  1646. SesId,
  1647. TblId,
  1648. pRowInfo,
  1649. pRowInfo->TimeStamp - ((pRowInfo->OwnerId == NMSDB_LOCAL_OWNER_ID) ? WinsCnf.RefreshInterval : WinsCnf.VerifyInterval),
  1650. pStatusInfo,
  1651. pStatusInfo->fStatic,
  1652. &fIsMem
  1653. ) != WINS_SUCCESS)
  1654. {
  1655. return(WINS_FAILURE);
  1656. }
  1657. //
  1658. // If all members are expired, then
  1659. // mark entry in conflict as a
  1660. // RELEASED (for the benefit of
  1661. // ClashAtRegGrp and ClashAtReplGrpMemR)
  1662. //
  1663. if (pStatusInfo->NodeAdds.NoOfMems == 0)
  1664. {
  1665. pStatusInfo->EntryState_e =
  1666. NMSDB_E_RELEASED;
  1667. }
  1668. }
  1669. else
  1670. {
  1671. pStatusInfo->NodeAdds.NoOfMems = 0;
  1672. }
  1673. }
  1674. }
  1675. #if !NEW_OWID
  1676. pStatusInfo->OwnerId = 0;
  1677. #endif
  1678. /*
  1679. Retrieve the owner Id column.
  1680. */
  1681. CALL_M(
  1682. JetRetrieveColumn(
  1683. SesId,
  1684. TblId,
  1685. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  1686. &pStatusInfo->OwnerId,
  1687. NAM_ADD_OWNERID_SIZE,
  1688. &ActFldLen,
  1689. 0,
  1690. NULL
  1691. )
  1692. );
  1693. //
  1694. // Just in case we challenge this entry and it
  1695. // happens to be multihomed, we would need to add
  1696. // it as a member (see ProcAddList).
  1697. //
  1698. if (NMSDB_ENTRY_UNIQUE_M(pStatusInfo->EntTyp))
  1699. {
  1700. pStatusInfo->NodeAdds.Mem[0].OwnerId =
  1701. pStatusInfo->OwnerId;
  1702. if (pStatusInfo->OwnerId ==
  1703. NMSDB_LOCAL_OWNER_ID)
  1704. {
  1705. //
  1706. // Put the current time stamp as the time
  1707. // stamp of the member. Though not strictly
  1708. // correct, it is ok. We don't
  1709. // need to retrieve the time stamp of the
  1710. // conflicting record this way.
  1711. //
  1712. pStatusInfo->NodeAdds.Mem[0].TimeStamp
  1713. = pRowInfo->TimeStamp;
  1714. }
  1715. }
  1716. //
  1717. // If the conflicting record is owned by the local
  1718. // WINS, we must retrieve the version number. This
  1719. // is used to determine whether the special record
  1720. // storing the highest version number of the
  1721. // local records should be updated (refer:
  1722. // NmsDbUpdateRow, NmsDbSeekNUpd, NmsScvDoScavenging, // NmsDbUpdHighestVersNoRec)
  1723. //
  1724. if (pStatusInfo->OwnerId == NMSDB_LOCAL_OWNER_ID)
  1725. {
  1726. //
  1727. // Retrieve the version number
  1728. //
  1729. CALL_M( JetRetrieveColumn(
  1730. SesId,
  1731. TblId,
  1732. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  1733. &(pStatusInfo->VersNo),
  1734. sizeof(VERS_NO_T),
  1735. &ActFldLen,
  1736. 0,
  1737. NULL
  1738. )
  1739. );
  1740. }
  1741. // break; //break out of the while loop
  1742. }
  1743. else
  1744. {
  1745. #if 0
  1746. if (!fWaitDone)
  1747. {
  1748. WINSEVT_LOG_INFO_M(
  1749. WINS_SUCCESS,
  1750. WINS_EVT_CANT_FIND_REC
  1751. );
  1752. Sleep(10); //sleep for 10 msecs to let
  1753. //the other
  1754. //thread commit/rollback the
  1755. //transaction that is
  1756. //inserting a record that
  1757. //caused a conflict
  1758. //
  1759. // Set flag to TRUE so that if we get the same
  1760. // error again, we can log an error and raise
  1761. // an exception
  1762. //
  1763. fWaitDone = TRUE;
  1764. continue; //iterate one more time
  1765. }
  1766. #endif
  1767. /*
  1768. * We should never get here. Something major is wrong.
  1769. * Either our current index is not on the name column or
  1770. * there is something wrong with JET
  1771. */
  1772. DBGPRINT1(EXC, "NmsDbInsertRowGrp: Could not seek to conflicting record. WEIRD. Error is (%d)\n", JetRetStat);
  1773. ASSERTMSG(0, "SEEK ERROR");
  1774. WINSEVT_LOG_M(JetRetStat, WINS_EVT_F_CANT_FIND_REC);
  1775. WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
  1776. }
  1777. } // not a duplicate
  1778. CALL_M(JetRetStat);
  1779. return(WINS_SUCCESS);
  1780. }
  1781. STATUS
  1782. NmsDbRelRow(
  1783. IN PNMSDB_ROW_INFO_T pRowInfo,
  1784. OUT PNMSDB_STAT_INFO_T pStatusInfo
  1785. )
  1786. /*++
  1787. Routine Description:
  1788. This function releases a record in the database. Releasing
  1789. requires
  1790. mark state as released
  1791. update time stamp
  1792. mark self as owner
  1793. Arguments:
  1794. pRowInfo - Information about the record to release
  1795. pStatusInfo - Status of operation
  1796. Externals Used:
  1797. None
  1798. Return Value:
  1799. Success status codes -- WINS_SUCCESS
  1800. Error status codes -- WINS_FAILURE
  1801. Error Handling:
  1802. Called by:
  1803. NmsNmhNamRelRow
  1804. Side Effects:
  1805. Comments:
  1806. None
  1807. --*/
  1808. {
  1809. DWORD FldNo = 0;
  1810. JET_ERR JetRetStat;
  1811. DWORD Ownerid = NMSDB_LOCAL_OWNER_ID;
  1812. #if NEW_OWID
  1813. DWORD OldOwnerId;
  1814. #else
  1815. DWORD OldOwnerId = 0;
  1816. #endif
  1817. DWORD FlagVal = 0; //flag value of record that is retrieved
  1818. DWORD ActFldLen = 0; //length of fld retrieved
  1819. BOOL fFound = FALSE; //set to TRUE if Address is found in group
  1820. BOOL fToRelease = TRUE; //will be changed to false only for
  1821. //a special group
  1822. JET_TABLEID TblId;
  1823. JET_SESID SesId;
  1824. PWINSTHD_TLS_T pTls;
  1825. JET_RETINFO RetInfo;
  1826. BYTE EntTyp;
  1827. #ifdef WINSDBG
  1828. BOOL fUpd = FALSE;
  1829. #endif
  1830. GET_TLS_M(pTls);
  1831. ASSERT(pTls != NULL);
  1832. TblId = pTls->NamAddTblId;
  1833. SesId = pTls->SesId;
  1834. pStatusInfo->StatCode = NMSDB_SUCCESS;
  1835. CALL_M( JetMakeKey(
  1836. SesId,
  1837. TblId,
  1838. pRowInfo->pName,
  1839. pRowInfo->NameLen,
  1840. JET_bitNewKey
  1841. )
  1842. );
  1843. if ( (JetRetStat = JetSeek(
  1844. SesId,
  1845. TblId,
  1846. JET_bitSeekEQ
  1847. )
  1848. ) == JET_errRecordNotFound
  1849. )
  1850. {
  1851. /*
  1852. We return success, since the record is not there.
  1853. This situation can happen under the following
  1854. condition.
  1855. The client sends a name release to another WINS
  1856. which has not yet got the replica of the record.
  1857. In the second case above, returning a positive name release
  1858. request is ok even though the entry has not been released.
  1859. It will eventually get released as a result of it not being
  1860. refreshed or at the occurrence of a conflict.
  1861. */
  1862. NOTE("Currently, NETBT always goes to the local WINS server for registrations")
  1863. NOTE("So, if a record is not in this db, it better not be in netbt tables too")
  1864. NOTE("If NETBT changes the above semantic in the future i.e. starts going")
  1865. NOTE("to a non-local WINS for reg., we should set pStatusInfo->fLocal to TRUE")
  1866. NOTE("here")
  1867. return(WINS_SUCCESS);
  1868. }
  1869. else
  1870. {
  1871. if (JetRetStat != JET_errSuccess)
  1872. {
  1873. DBGPRINT1(ERR,
  1874. "NmsDbRelRow: Seek returned Error (%d)\n",
  1875. JetRetStat);
  1876. return(WINS_FAILURE);
  1877. }
  1878. }
  1879. // retrieve the flags column
  1880. CALL_M( JetRetrieveColumn(
  1881. SesId,
  1882. TblId,
  1883. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  1884. &FlagVal,
  1885. sizeof(FlagVal),
  1886. &ActFldLen,
  1887. 0,
  1888. NULL
  1889. )
  1890. );
  1891. //
  1892. // Set the fLocal flag if this entry was registered by this node
  1893. //
  1894. pStatusInfo->fLocal = NMSDB_IS_ENTRY_LOCAL_M(FlagVal);
  1895. if (!NMSDB_ENTRY_ACT_M(FlagVal))
  1896. {
  1897. /*
  1898. The entry is already released. This can happen
  1899. because of the following reasons
  1900. --client sent a repeat name release since it did not
  1901. get the response to the earlier one (maybe it got
  1902. lost or maybe because of a timing window where WINS
  1903. has sent a response just around the time the client
  1904. does the retry
  1905. --entry got released due to no refresh (all refreshes got
  1906. lost.
  1907. Returning a positive name release is fine. If the client
  1908. has not got the first one (because it got lost, it will get
  1909. the second one). If it has now received the first response,
  1910. it will just ignore the second one
  1911. */
  1912. CHECK("Make sure that NBT will ignore the second one")
  1913. return(WINS_SUCCESS);
  1914. }
  1915. EntTyp = (BYTE)NMSDB_ENTRY_TYPE_M(FlagVal);
  1916. //
  1917. // If we got a release for a unique entry but the entry
  1918. // we found is a group entry or vice-versa, return
  1919. // NO_SUCH_ROW status.
  1920. //
  1921. if (
  1922. (
  1923. NMSDB_ENTRY_UNIQUE_M(EntTyp)
  1924. &&
  1925. NMSDB_ENTRY_GRP_M(pRowInfo->EntTyp)
  1926. )
  1927. ||
  1928. (
  1929. NMSDB_ENTRY_GRP_M(EntTyp)
  1930. &&
  1931. !NMSDB_ENTRY_GRP_M(pRowInfo->EntTyp)
  1932. )
  1933. )
  1934. {
  1935. DBGPRINT0(ERR, "NmsDbRelRow: Request to release a record with a type (unique/group) than the one for which the release was sent has been ignored\n");
  1936. PERF("Remove this logging to increase speed")
  1937. // per bug #336889 remove this
  1938. // WINSEVT_LOG_D_M(WINS_FAILURE, WINS_EVT_REL_TYP_MISMATCH);
  1939. pStatusInfo->StatCode = NMSDB_NO_SUCH_ROW;
  1940. return(WINS_SUCCESS);
  1941. }
  1942. pStatusInfo->EntTyp = (BYTE)NMSDB_ENTRY_TYPE_M(FlagVal);
  1943. //
  1944. // If it is a dynamic release request but the entry found is STATIC,
  1945. // we return SUCCESS.
  1946. //
  1947. // Note: Even though the address in the release request may be
  1948. // different from one in the STATIC record, we return SUCCESS.
  1949. //
  1950. // This is to save overhead for the majority of cases (99%) where
  1951. // the addresses are going to be the same.
  1952. //
  1953. if (!pRowInfo->fAdmin && (NMSDB_IS_ENTRY_STATIC_M(FlagVal) &&
  1954. !NMSDB_ENTRY_USER_SPEC_GRP_M(pRowInfo->pName, pStatusInfo->EntTyp)))
  1955. {
  1956. return(WINS_SUCCESS);
  1957. }
  1958. if (pStatusInfo->EntTyp == NMSDB_UNIQUE_ENTRY)
  1959. {
  1960. /* retrieve the ip address column*/
  1961. RetInfo.itagSequence = 1;
  1962. RetInfo.cbStruct = sizeof(JET_RETINFO);
  1963. RetInfo.ibLongValue = 0;
  1964. CALL_M( JetRetrieveColumn(
  1965. SesId,
  1966. TblId,
  1967. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  1968. &(pStatusInfo->NodeAdds.Mem[0].Add),
  1969. sizeof(COMM_ADD_T),
  1970. &ActFldLen,
  1971. 0,
  1972. &RetInfo
  1973. )
  1974. );
  1975. pStatusInfo->NodeAdds.NoOfMems = 1;
  1976. //
  1977. // Extract the Node Type from the Flags byte
  1978. //
  1979. pStatusInfo->NodeTyp = (BYTE)NMSDB_NODE_TYPE_M(FlagVal);
  1980. //
  1981. // if the address of the entry to be released does not
  1982. // match the address of the client requesting the release
  1983. // and it is not an administrative action, we do not release
  1984. // the entry
  1985. //
  1986. if (
  1987. (pRowInfo->pNodeAdd->Add.IPAdd !=
  1988. pStatusInfo->NodeAdds.Mem[0].Add.Add.IPAdd)
  1989. &&
  1990. (!pRowInfo->fAdmin)
  1991. )
  1992. {
  1993. DBGPRINT3(ERR, "NmsDbRelRow: Request to release a record (%s) with a different IP address (%x) than that in the release request (%x) has been ignored\n", pRowInfo->pName, pRowInfo->pNodeAdd->Add.IPAdd, pStatusInfo->NodeAdds.Mem[0].Add.Add.IPAdd);
  1994. pStatusInfo->StatCode = NMSDB_NO_SUCH_ROW;
  1995. #if 0 //per bug #336875
  1996. if (WinsCnf.LogDetailedEvts)
  1997. {
  1998. WinsEvtLogDetEvt(TRUE, WINS_EVT_REL_ADD_MISMATCH, TEXT("nmsdb"), __LINE__, "sdd", pRowInfo->pName, pRowInfo->pNodeAdd->Add.IPAdd,
  1999. pStatusInfo->NodeAdds.Mem[0].Add.Add.IPAdd);
  2000. }
  2001. #endif
  2002. // WINSEVT_LOG_D_M(WINS_FAILURE, WINS_EVT_REL_ADD_MISMATCH);
  2003. return(WINS_SUCCESS);
  2004. }
  2005. }
  2006. else // it is a group entry (Normal or Special) or a multihomed entry
  2007. {
  2008. //
  2009. // if it is a special group/multihomed entry, we need to do a
  2010. // number of things
  2011. //
  2012. if (!NMSDB_ENTRY_NORM_GRP_M(pStatusInfo->EntTyp))
  2013. {
  2014. BOOL fIsMem;
  2015. //
  2016. // Init the following fields since they are used to
  2017. // by GetGrpMem (for determining fIsMem)
  2018. //
  2019. pRowInfo->NodeAdds.NoOfMems = 1;
  2020. pRowInfo->NodeAdds.Mem[0].Add = *(pRowInfo->pNodeAdd);
  2021. //
  2022. // get all non-expired group/multihomed members
  2023. //
  2024. if (GetGrpMem(
  2025. SesId,
  2026. TblId,
  2027. pRowInfo,
  2028. pRowInfo->TimeStamp,
  2029. pStatusInfo,
  2030. NMSDB_IS_ENTRY_STATIC_M(FlagVal),
  2031. &fIsMem
  2032. ) != WINS_SUCCESS)
  2033. {
  2034. return(WINS_FAILURE);
  2035. }
  2036. //
  2037. // If client is not a member of the group (maybe it
  2038. // never registered or if it did, maybe its entry
  2039. // has timed out.) We return SUCCESS
  2040. //
  2041. CHECK("Maybe we should return NO_SUCH_ROW here. This will then result")
  2042. CHECK("in a NAM_ERR being returned to the client. Also, is there any")
  2043. CHECK("need to keep members around even if they have timed out just so")
  2044. CHECK("that we don't release a spec. group due to a request from a client")
  2045. CHECK("that was never a member. ")
  2046. if ((!fIsMem) || (pStatusInfo->NodeAdds.NoOfMems == 0))
  2047. {
  2048. pStatusInfo->StatCode = NMSDB_SUCCESS;
  2049. return(WINS_SUCCESS);
  2050. }
  2051. else //client is a member of the group/multihomed list
  2052. {
  2053. DWORD i;
  2054. DWORD n = 0;
  2055. //
  2056. // Save the address of the client in a local
  2057. // var.
  2058. //
  2059. COMM_IP_ADD_T IPAdd =
  2060. pRowInfo->NodeAdds.Mem[0].
  2061. Add.Add.IPAdd;
  2062. //
  2063. // Init the no. of mems fields of the address
  2064. // structure to store to 0
  2065. //
  2066. pRowInfo->NodeAdds.NoOfMems = 0;
  2067. //
  2068. // remove the client from the active list by
  2069. // storing all other members in the NodeAdds
  2070. // field of ROW_INFO_T structure. Note:
  2071. // if there is an address match, we remove
  2072. // the member irrespective of its ownership.
  2073. // Also note: This code is not reachable
  2074. // for a static record (see above)
  2075. // unless it is an admin request.
  2076. //
  2077. for (i = 0;
  2078. i < pStatusInfo->NodeAdds.NoOfMems;
  2079. i++
  2080. )
  2081. {
  2082. if (
  2083. pStatusInfo->NodeAdds.Mem[i].Add.Add.IPAdd
  2084. != IPAdd )
  2085. {
  2086. pRowInfo->NodeAdds.Mem[n++]
  2087. = pStatusInfo->NodeAdds.Mem[i];
  2088. pRowInfo->NodeAdds.NoOfMems++;
  2089. }
  2090. }
  2091. //
  2092. // If there is at least one group/multihomed
  2093. // member, we do not release the row
  2094. //
  2095. if (pRowInfo->NodeAdds.NoOfMems != 0)
  2096. {
  2097. fToRelease = FALSE;
  2098. }
  2099. } //end of else
  2100. }
  2101. }
  2102. /*
  2103. * Retrieve the owner Id column.
  2104. */
  2105. CALL_M(
  2106. JetRetrieveColumn(
  2107. SesId,
  2108. TblId,
  2109. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  2110. &OldOwnerId,
  2111. NAM_ADD_OWNERID_SIZE,
  2112. &ActFldLen,
  2113. 0,
  2114. NULL
  2115. )
  2116. );
  2117. CALL_M(JetBeginTransaction(SesId));
  2118. try {
  2119. JetRetStat = JetPrepareUpdate(
  2120. SesId,
  2121. TblId,
  2122. JET_prepReplace
  2123. );
  2124. if (
  2125. (JetRetStat != JET_errSuccess)
  2126. &&
  2127. (JetRetStat != JET_wrnNoWriteLock)
  2128. )
  2129. {
  2130. RET_M(JetRetStat);
  2131. }
  2132. //
  2133. // If we have to release a record not owned by us, let us change
  2134. // it into a tombstone. This will result in replication of the same.
  2135. // We want this to shorten the db inconsistency window between our
  2136. // db and the db of the WINS that owns this record.
  2137. //
  2138. // Consider the following situation: Client A registers AA at WINS A
  2139. // It then releases AA at WINS B. On a reboot, it registers at WINS A.
  2140. // Subsequent refreshes also go to WINS A. Since AA was active at WINS
  2141. // A when the registration after the release (at B) came in, the
  2142. // version number wouldn't be incremented and so the record will not
  2143. // replicate again. B will continue to have the released record
  2144. // until it becomes a tombstone and gets replicated.
  2145. //
  2146. if (fToRelease)
  2147. {
  2148. //
  2149. // Get rid of released state altogether
  2150. //
  2151. if (OldOwnerId != Ownerid)
  2152. {
  2153. FlagVal |= (NMSDB_E_TOMBSTONE << NMSDB_SHIFT_STATE);
  2154. //
  2155. // Strictly speaking, for a record that has been turned into
  2156. // a tombstone, we should be using the tombstonetimeout value,
  2157. // we don't do that here. Since such a record never went through
  2158. // the released state, we set the expiry to the aggregate of the
  2159. // tombstone interval and tombstone timeout (to doubly safeguard
  2160. // against it getting deleted prematurely - long weekend and
  2161. // everything).
  2162. //
  2163. pRowInfo->TimeStamp +=
  2164. WinsCnf.TombstoneInterval + WinsCnf.TombstoneTimeout;
  2165. DBGPRINT3(DET, "NmsDbRelRow: Changing from ACTIVE TO TOMBSTONE. Name = (%s),Old and new OwnerId (%d/%d)\n",
  2166. pRowInfo->pName, OldOwnerId,Ownerid);
  2167. FUTURES("Use macro in winevt.h. Make it a warning")
  2168. #if 0 //per bug #336889
  2169. if (WinsCnf.LogDetailedEvts > 0)
  2170. {
  2171. WinsEvtLogDetEvt(TRUE, WINS_EVT_REL_DIFF_OWN, NULL, __LINE__, "sd", pRowInfo->pName,
  2172. OldOwnerId);
  2173. }
  2174. #endif
  2175. }
  2176. else
  2177. {
  2178. FlagVal |= (NMSDB_E_RELEASED << NMSDB_SHIFT_STATE);
  2179. pRowInfo->TimeStamp += WinsCnf.TombstoneInterval;
  2180. }
  2181. }
  2182. else //hit only for a special group/multihomed entry
  2183. {
  2184. pRowInfo->TimeStamp += WinsCnf.RefreshInterval;
  2185. //
  2186. //Set the address field with the new member list
  2187. //
  2188. CALL_M( InsertGrpMemsInCol(
  2189. SesId,
  2190. TblId,
  2191. pRowInfo,
  2192. JET_prepReplace
  2193. )
  2194. );
  2195. }
  2196. /*
  2197. Set flags column
  2198. Even though not required for special groups, we set it
  2199. to save ourselves an if test (an if test will impact 99% of the
  2200. client releases).
  2201. */
  2202. CALL_M( JetSetColumn(
  2203. SesId,
  2204. TblId,
  2205. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  2206. &FlagVal,
  2207. sizeof(FlagVal),
  2208. 0,
  2209. NULL /*optional info */
  2210. )
  2211. );
  2212. //
  2213. // Since we are taking over ownership of this record, we must
  2214. // update the version number also, else there can be a conflict
  2215. //
  2216. if (OldOwnerId != NMSDB_LOCAL_OWNER_ID)
  2217. {
  2218. /* Set the owner byte */
  2219. CALL_M( JetSetColumn(
  2220. SesId,
  2221. TblId,
  2222. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  2223. &Ownerid,
  2224. NAM_ADD_OWNERID_SIZE,
  2225. 0,
  2226. NULL /*optional info */
  2227. )
  2228. );
  2229. // set the the version number column
  2230. CALL_M( JetSetColumn(
  2231. SesId,
  2232. TblId,
  2233. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  2234. &(pRowInfo->VersNo),
  2235. sizeof(VERS_NO_T),
  2236. 0,
  2237. NULL /*optional info */
  2238. )
  2239. );
  2240. #ifdef WINSDBG
  2241. fUpd = TRUE;
  2242. pRowInfo->EntryState_e = NMSDB_E_RELEASED;
  2243. #endif
  2244. }
  2245. /* set the timestamp column */
  2246. CALL_M( JetSetColumn(
  2247. pTls->SesId,
  2248. TblId,
  2249. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  2250. &(pRowInfo->TimeStamp),
  2251. sizeof(DWORD), /*change type to TIME_STAMP_T
  2252. *later*/
  2253. 0,
  2254. NULL /*optional info */
  2255. )
  2256. );
  2257. #ifndef WINSDBG
  2258. CALL_M(JetUpdate (
  2259. SesId,
  2260. TblId,
  2261. NULL,
  2262. 0L,
  2263. NULL
  2264. )
  2265. );
  2266. #else
  2267. JetRetStat = JetUpdate ( SesId, TblId, NULL, 0L, NULL);
  2268. ASSERT(JetRetStat != JET_errKeyDuplicate);
  2269. if (JetRetStat == JET_errKeyDuplicate)
  2270. {
  2271. WinsEvtLogDetEvt(FALSE, WINS_EVT_DATABASE_UPD_ERR, NULL, __LINE__,
  2272. "sdd", pRowInfo->pName, Ownerid, FlagVal);
  2273. }
  2274. CALL_M(JetRetStat);
  2275. #endif
  2276. } // end of try block
  2277. finally {
  2278. if (AbnormalTermination())
  2279. {
  2280. // if there is an abnormal termination, we already have an error
  2281. // code here. We shouldn't override it with any other error code.
  2282. JetRollback(SesId, JET_bitRollbackAll);
  2283. }
  2284. else
  2285. {
  2286. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553).)
  2287. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  2288. CALL_M(JetCommitTransaction(SesId, JET_bitCommitFlush));
  2289. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  2290. if (OldOwnerId != NMSDB_LOCAL_OWNER_ID)
  2291. {
  2292. //
  2293. // No need to send any push notification since we do
  2294. // not wish to replicate this change.
  2295. //
  2296. // Also, no need to call NMSNMH_INC_VERS_COUNTER_M since
  2297. // it is ok not to check against threshold if the
  2298. // version number got incremented because of a release.
  2299. //
  2300. NMSNMH_INC_VERS_NO_M(NmsNmhMyMaxVersNo, NmsNmhMyMaxVersNo);
  2301. }
  2302. }
  2303. }
  2304. NMSNMH_UPD_UPD_CTRS_M(fUpd, TRUE, pRowInfo);
  2305. return(WINS_SUCCESS);
  2306. }
  2307. STATUS
  2308. NmsDbQueryRow(
  2309. IN PNMSDB_ROW_INFO_T pRowInfo,
  2310. OUT PNMSDB_STAT_INFO_T pStatusInfo
  2311. )
  2312. /*++
  2313. Routine Description:
  2314. This function queries a record in the database.
  2315. Arguments:
  2316. Externals Used:
  2317. None
  2318. Return Value:
  2319. Success status codes -- WINS_SUCCESS
  2320. Error status codes -- WINS_FAILURE
  2321. Error Handling:
  2322. Called by:
  2323. NmsNmhNamQuery
  2324. Side Effects:
  2325. Comments:
  2326. None
  2327. --*/
  2328. {
  2329. DWORD FldNo = 0;
  2330. DWORD FlagVal = 0; //flag value of record that is retrieved
  2331. DWORD ActFldLen = 0; //length of fld retrieved
  2332. BOOL fFound = FALSE; //set to TRUE if Address is found in group
  2333. JET_TABLEID TblId;
  2334. JET_SESID SesId;
  2335. PWINSTHD_TLS_T pTls;
  2336. STATUS RetStat = WINS_SUCCESS;
  2337. pStatusInfo->NodeAdds.NoOfMems = 1;
  2338. GET_TLS_M(pTls);
  2339. ASSERT(pTls != NULL);
  2340. TblId = pTls->NamAddTblId;
  2341. SesId = pTls->SesId;
  2342. pStatusInfo->StatCode = NMSDB_SUCCESS;
  2343. CALL_M(JetBeginTransaction(pTls->SesId));
  2344. try {
  2345. CALL_M( JetMakeKey(
  2346. SesId,
  2347. TblId,
  2348. pRowInfo->pName,
  2349. pRowInfo->NameLen,
  2350. JET_bitNewKey
  2351. )
  2352. );
  2353. if ( JetSeek(
  2354. SesId,
  2355. TblId,
  2356. JET_bitSeekEQ
  2357. ) == JET_errSuccess
  2358. )
  2359. {
  2360. // retrieve the flags column
  2361. CALL_M( JetRetrieveColumn(
  2362. SesId,
  2363. TblId,
  2364. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  2365. &FlagVal,
  2366. sizeof(FlagVal),
  2367. &ActFldLen,
  2368. 0,
  2369. NULL
  2370. )
  2371. );
  2372. pStatusInfo->EntTyp = (BYTE)NMSDB_ENTRY_TYPE_M(FlagVal);
  2373. pStatusInfo->fLocal = NMSDB_IS_ENTRY_LOCAL_M(FlagVal);
  2374. pStatusInfo->NodeTyp = (BYTE)((FlagVal & NMSDB_BIT_NODE_TYP) >> NMSDB_SHIFT_NODE_TYP);
  2375. if (pStatusInfo->EntTyp == NMSDB_UNIQUE_ENTRY)
  2376. {
  2377. /* It is a unique entry*/
  2378. /*
  2379. * check the flag field to determine if it is
  2380. * released or a tombstone. Get the address if
  2381. * the entry is ACTIVE or if it is an admin query
  2382. */
  2383. if ((NMSDB_ENTRY_ACT_M(FlagVal)) || pRowInfo->fAdmin)
  2384. {
  2385. JET_RETINFO RetInfo;
  2386. /* retrieve the ip address column*/
  2387. RetInfo.itagSequence = 1;
  2388. RetInfo.cbStruct = sizeof(JET_RETINFO);
  2389. RetInfo.ibLongValue = 0;
  2390. CALL_M( JetRetrieveColumn(
  2391. SesId,
  2392. TblId,
  2393. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  2394. &(pStatusInfo->NodeAdds.Mem[0].Add),
  2395. sizeof(COMM_ADD_T),
  2396. &ActFldLen,
  2397. 0,
  2398. &RetInfo
  2399. )
  2400. );
  2401. pStatusInfo->NodeAdds.NoOfMems = 1;
  2402. }
  2403. else // the unique entry is released or a tombstone
  2404. {
  2405. /*
  2406. If the state is anything other than active, return
  2407. no such row
  2408. */
  2409. pStatusInfo->StatCode = NMSDB_NO_SUCH_ROW;
  2410. }
  2411. }
  2412. else // it is a group/multihomed record
  2413. {
  2414. /*
  2415. Check whether this is a normal group or a special group.
  2416. For normal group, we return the subnet broadcast
  2417. address. This means that we have to find the subnet
  2418. mask for the network from which the request came.
  2419. For now, we return all 1s (-1). This
  2420. indicates the broadcast address on the
  2421. local subnet (Vol 1, 2, 3 of Comer for the naive)
  2422. */
  2423. if (pStatusInfo->EntTyp == NMSDB_NORM_GRP_ENTRY)
  2424. {
  2425. DBGPRINT0(FLOW, "Record queried is a normal group record\n");
  2426. //
  2427. // If it is not a TOMBSTONE, return the subnet mask.
  2428. // We return the subnet mask even when the state is
  2429. // RELEASED because the group may be active at another
  2430. // WINS server
  2431. //
  2432. if (!(NMSDB_ENTRY_TOMB_M(FlagVal)) || pRowInfo->fAdmin)
  2433. {
  2434. pStatusInfo->NodeAdds.Mem[0].Add.Add.IPAdd = 0xFFFFFFFF;
  2435. }
  2436. else //state is tombstone
  2437. {
  2438. pStatusInfo->StatCode = NMSDB_NO_SUCH_ROW;
  2439. }
  2440. }
  2441. else // it is a special group/multihomed entry
  2442. {
  2443. BOOL fIsMem;
  2444. DBGPRINT1(FLOW, "Record queried is a %s record\n",
  2445. NMSDB_ENTRY_SPEC_GRP_M(pStatusInfo->EntTyp) ?
  2446. "SPECIAL GROUP" : "MULTIHOMED");
  2447. #if 0
  2448. //NOTE: No need to do the following, since we don't care about the value of
  2449. //fIsMem returned GetGrpMem()
  2450. pRowInfo->NodeAdds.NoOfMems = 1;
  2451. pRowInfo->NodeAdds.Mem[0].Add = *(pRowInfo->pNodeAdd);
  2452. #endif
  2453. //
  2454. // We return only the active members.
  2455. //
  2456. // Remember:
  2457. // A special group/multihomed entry is released when
  2458. // all its members have timed out. A member times out
  2459. // only if it is a non-STATIC entry, is owned by the
  2460. // local WINS, and has not been refreshed within the
  2461. // refresh time interval. All owned entries get
  2462. // released if they are not refreshed. A member also
  2463. // gets removed if a release is received for it.
  2464. // Now, an owned multihomed entry/special group can have
  2465. // members owned by other WINS servers. The only member we
  2466. // may get is one that belongs to the local WINS
  2467. // for which the WINS got a release earlier (but
  2468. // the member was not removed)
  2469. //
  2470. if (NMSDB_ENTRY_ACT_M(FlagVal) || pRowInfo->fAdmin )
  2471. {
  2472. //
  2473. // Get all non-expired members unless it is
  2474. // is a STATIC record in which case get all
  2475. // members regardless of whether or not they
  2476. // have expired.
  2477. //
  2478. // NOTE: For some cases we also want to return expired
  2479. // members. e.g WINSA has name FOO with members (A,B)
  2480. // and WINSB has name FOO with members B. WINSA owns the
  2481. // member B. When B is expired on WINSA and if the replication
  2482. // is broken for extended period of time, then we still
  2483. // want to return member B from WINSA. Consider passing TRUE
  2484. // for the fStatic parameter.
  2485. GetGrpMem(
  2486. SesId,
  2487. TblId,
  2488. pRowInfo,
  2489. pRowInfo->TimeStamp,
  2490. pStatusInfo,
  2491. NMSDB_IS_ENTRY_STATIC_M(FlagVal),
  2492. &fIsMem
  2493. );
  2494. if ((pStatusInfo->NodeAdds.NoOfMems == 0)
  2495. && !pRowInfo->fAdmin)
  2496. {
  2497. pStatusInfo->StatCode =
  2498. NMSDB_NO_SUCH_ROW;
  2499. }
  2500. }
  2501. else //special group/multihomed entry is a tombstone
  2502. {
  2503. pStatusInfo->NodeAdds.NoOfMems = 0;
  2504. pStatusInfo->StatCode = NMSDB_NO_SUCH_ROW;
  2505. }
  2506. //
  2507. // If the group/multihomed entry does not have any
  2508. // members (i.e. all members have timed out, change
  2509. // the state of the entry to RELEASED
  2510. //
  2511. FUTURES("Maybe change the state of the group to released now")
  2512. } // it is a special group or multihomed entry
  2513. }
  2514. }
  2515. else
  2516. {
  2517. RetStat = WINS_FAILURE;
  2518. }
  2519. //
  2520. // If this function was invoked in an RPC thread and all
  2521. // operation upto now have succeeded, let us get the owner Id and
  2522. // version number of the record
  2523. //
  2524. if ((pRowInfo->fAdmin) && (RetStat == WINS_SUCCESS))
  2525. {
  2526. pStatusInfo->EntryState_e = NMSDB_ENTRY_STATE_M(FlagVal);
  2527. pStatusInfo->fStatic = NMSDB_IS_ENTRY_STATIC_M(FlagVal);
  2528. #if !NEW_OWID
  2529. pStatusInfo->OwnerId = 0;
  2530. #endif
  2531. /*
  2532. * Retrieve the owner Id column.
  2533. */
  2534. CALL_M(
  2535. JetRetrieveColumn(
  2536. SesId,
  2537. TblId,
  2538. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  2539. &pStatusInfo->OwnerId,
  2540. NAM_ADD_OWNERID_SIZE,
  2541. &ActFldLen,
  2542. 0,
  2543. NULL
  2544. )
  2545. );
  2546. //
  2547. // Retrieve the version number
  2548. //
  2549. CALL_M( JetRetrieveColumn(
  2550. SesId,
  2551. TblId,
  2552. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  2553. &(pStatusInfo->VersNo),
  2554. sizeof(VERS_NO_T),
  2555. &ActFldLen,
  2556. 0,
  2557. NULL
  2558. )
  2559. );
  2560. //
  2561. // get the timestamp field
  2562. //
  2563. CALL_M( JetRetrieveColumn(
  2564. SesId,
  2565. TblId,
  2566. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  2567. &(pStatusInfo->TimeStamp),
  2568. sizeof(pStatusInfo->TimeStamp),
  2569. &ActFldLen,
  2570. 0,
  2571. NULL
  2572. )
  2573. );
  2574. }
  2575. }
  2576. finally {
  2577. JET_ERR JetRetStat;
  2578. JetRetStat = JetRollback(pTls->SesId, JET_bitRollbackAll);
  2579. if (!AbnormalTermination())
  2580. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  2581. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  2582. CALL_M(JetRetStat);
  2583. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  2584. }
  2585. return(RetStat);
  2586. }
  2587. STATUS
  2588. NmsDbUpdateRow(
  2589. IN PNMSDB_ROW_INFO_T pRowInfo,
  2590. OUT PNMSDB_STAT_INFO_T pStatusInfo
  2591. )
  2592. /*++
  2593. Routine Description:
  2594. This function replaces a conflicting row in the database with the
  2595. row passed. It expects the currency to be on the record
  2596. Arguments:
  2597. pRowInfo - Information about the record to insert/replace
  2598. pStatusInfo - Status of operation and information about the conflicting
  2599. record if the update resulted in a conlfict (only for
  2600. an insert)
  2601. Externals Used:
  2602. None
  2603. Return Value:
  2604. Success status codes -- WINS_SUCCESS
  2605. Error status codes -- WINS_FAILURE
  2606. Error Handling:
  2607. Called by:
  2608. NBT request thread -- NmsNmhNamRegInd()
  2609. Side Effects:
  2610. Comments:
  2611. None
  2612. --*/
  2613. {
  2614. JET_TABLEID TblId;
  2615. JET_SESID SesId;
  2616. PWINSTHD_TLS_T pTls;
  2617. #ifdef WINSDBG
  2618. JET_ERR JetRetStat;
  2619. #endif
  2620. pTls = TlsGetValue(WinsTlsIndex);
  2621. // No need to check whether pTls is NON-NULL. It has to be
  2622. TblId = pTls->NamAddTblId;
  2623. SesId = pTls->SesId;
  2624. pStatusInfo->StatCode = NMSDB_SUCCESS;
  2625. #ifndef WINSDBG
  2626. /*
  2627. * Replace the row
  2628. */
  2629. CALL_M(
  2630. UpdateDb(
  2631. SesId,
  2632. TblId,
  2633. pRowInfo,
  2634. JET_prepReplace
  2635. )
  2636. );
  2637. #else
  2638. JetRetStat = UpdateDb( SesId, TblId, pRowInfo, JET_prepReplace );
  2639. if (JetRetStat == JET_errKeyDuplicate)
  2640. {
  2641. BYTE Tmp[20];
  2642. WinsEvtLogDetEvt(FALSE, WINS_EVT_DB_ERR, NULL, __LINE__,
  2643. "sssdd", pRowInfo->pName, _itoa(pRowInfo->VersNo.LowPart, Tmp, 10), _itoa(pStatusInfo->VersNo.LowPart, Tmp, 10), pRowInfo->OwnerId, pStatusInfo->OwnerId);
  2644. DBGPRINT5(ERR, "NmsDbUpdateRow: Could not replace row\nName=(%s);Owner id = (%d);Vers. no = (%d)\nNew owner id = (%d); New Vers.No = (%d)\n",
  2645. pRowInfo->pName, pStatusInfo->OwnerId, pStatusInfo->VersNo.LowPart,
  2646. pRowInfo->OwnerId, pRowInfo->VersNo.LowPart);
  2647. return(WINS_FAILURE);
  2648. }
  2649. else
  2650. {
  2651. CALL_M(JetRetStat);
  2652. }
  2653. #endif
  2654. //
  2655. // NOTE: This call must be made after the UpdateDb above
  2656. // because otherwise we will need to seek to the record
  2657. // to be replaced
  2658. //
  2659. UpdHighestVersNoRecIfReqd(pTls, pRowInfo, pStatusInfo);
  2660. return(WINS_SUCCESS);
  2661. }
  2662. STATUS
  2663. NmsDbSeekNUpdateRow(
  2664. PNMSDB_ROW_INFO_T pRowInfo,
  2665. PNMSDB_STAT_INFO_T pStatusInfo
  2666. )
  2667. /*++
  2668. Routine Description:
  2669. This function seeks to a conflicting record and then replaces it
  2670. in the database with the row passed.
  2671. Arguments:
  2672. pRowInfo - Contains name to query
  2673. pStatusInfo - Information about the name queried
  2674. Externals Used:
  2675. None
  2676. Return Value:
  2677. Success status codes -- WINS_SUCCESS
  2678. Error status codes -- WINS_FAILURE
  2679. Error Handling:
  2680. Called by:
  2681. ChlUpdDb (Name Challenge thread) in NmsChl.c
  2682. Side Effects:
  2683. Comments:
  2684. Currently, this function is called only by the Name Challenge manager.
  2685. When it starts getting called by another component, we would need
  2686. to make sure that comparison of the owner id. retrieved from the
  2687. row to be replaced with the one we retrieved prior to handing the
  2688. request to the name challenge manager is the correct action for all
  2689. situations.
  2690. --*/
  2691. {
  2692. JET_TABLEID TblId;
  2693. JET_SESID SesId;
  2694. PWINSTHD_TLS_T pTls;
  2695. #if NEW_OWID
  2696. DWORD OwnerId;
  2697. #else
  2698. DWORD OwnerId = 0;
  2699. #endif
  2700. DWORD ActFldLen;
  2701. JET_ERR JetRetStat;
  2702. STATUS RetStat = WINS_SUCCESS;
  2703. pTls = TlsGetValue(WinsTlsIndex);
  2704. //
  2705. // No need to check whether pTls is NON-NULL. It has to be
  2706. //
  2707. TblId = pTls->NamAddTblId;
  2708. SesId = pTls->SesId;
  2709. pStatusInfo->StatCode = NMSDB_SUCCESS;
  2710. CALL_M( JetMakeKey(
  2711. SesId,
  2712. TblId,
  2713. pRowInfo->pName,
  2714. pRowInfo->NameLen,
  2715. JET_bitNewKey
  2716. )
  2717. );
  2718. if ((JetRetStat = JetSeek(
  2719. SesId,
  2720. TblId,
  2721. JET_bitSeekEQ
  2722. )) == JET_errSuccess
  2723. )
  2724. {
  2725. //
  2726. // Before replacing the row, let us check whether it is still
  2727. // owned by the same owner. We check this because during the
  2728. // window in which this challenge thread was working, the
  2729. // replicator might have pulled in records from another WINS
  2730. // server and updated the row with another row or a local
  2731. // nbt request might have resulted in the row getting updated
  2732. // (if it was a replica first). In either of the two cases
  2733. // above, we do not want to update the row.
  2734. //
  2735. /*
  2736. * Retrieve the owner Id column.
  2737. */
  2738. CALL_M(
  2739. JetRetrieveColumn(
  2740. SesId,
  2741. TblId,
  2742. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  2743. &OwnerId,
  2744. NAM_ADD_OWNERID_SIZE,
  2745. &ActFldLen,
  2746. 0,
  2747. NULL
  2748. )
  2749. );
  2750. if (OwnerId == pStatusInfo->OwnerId)
  2751. {
  2752. /*
  2753. * Replace the row
  2754. */
  2755. CALL_M(
  2756. UpdateDb(
  2757. SesId,
  2758. TblId,
  2759. pRowInfo,
  2760. JET_prepReplace
  2761. )
  2762. );
  2763. //
  2764. // NOTE: This call must be made after the UpdateDb above
  2765. // because otherwise we will need to seek to the record
  2766. // to be replaced
  2767. //
  2768. UpdHighestVersNoRecIfReqd(pTls, pRowInfo, pStatusInfo);
  2769. }
  2770. }
  2771. else
  2772. {
  2773. /*
  2774. * Means that some other thread (other than challenger),
  2775. * deleted the record. It has to be an rpc thread since
  2776. * an NBT thread would release the record, not delete it
  2777. */
  2778. WINSEVT_LOG_M(JetRetStat, WINS_EVT_F_CANT_FIND_REC);
  2779. RetStat = WINS_FAILURE;
  2780. // WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
  2781. }
  2782. return(RetStat);
  2783. }
  2784. STATUS
  2785. NmsDbGetDataRecs(
  2786. IN WINS_CLIENT_E Client_e,
  2787. IN OPTIONAL INT ThdPrLvl,
  2788. IN VERS_NO_T MinVersNo,
  2789. IN VERS_NO_T MaxVersNo,
  2790. IN DWORD MaxNoOfRecsReqd,
  2791. IN BOOL fUpToLimit,
  2792. IN BOOL fOnlyReplTomb OPTIONAL,
  2793. IN PNMSSCV_CLUT_T pClutter,
  2794. IN OUT PCOMM_ADD_T pWinsAdd,
  2795. IN BOOL fOnlyDynRecs,
  2796. IN DWORD RplType,
  2797. OUT LPVOID *ppRBuf,
  2798. OUT LPDWORD pRspBufLen,
  2799. OUT LPDWORD pNoOfRecs
  2800. )
  2801. /*++
  2802. Routine Description:
  2803. This function returns all the records in the range MinVersNo to
  2804. MaxVersNo that are owned by the WINS server at address pWinsAdd.
  2805. Arguments:
  2806. Client_e - id of client that called this function (Pull handler in
  2807. replicator or the scavenger thread)
  2808. ThdPrLvl - priority level of the scavenger thread
  2809. MinVersNo, MaxVersNo - range of version numbers to retrieve
  2810. MaxNoOfRecsReqd - Max. number of records required
  2811. fUpToLimit - Set to TRUE, if the max. version number arg is to
  2812. be ignored and records upto the last one in the db
  2813. have to be retrieved
  2814. fOnlyReplTomb - Only tombstones desired (valid if Client_e is NMSSCV)
  2815. pWinsAdd - Wins whose records need to be retrieved (owner WINS)
  2816. ppRbuf - Buffer to contain the records
  2817. pRspBufLen - size of the buffer
  2818. pNoOfRecs - No of records in the buffer
  2819. Externals Used:
  2820. None
  2821. Return Value:
  2822. Success status codes -- WINS_SUCCESS
  2823. Error status codes -- WINS_FAILURE
  2824. Error Handling:
  2825. Called by:
  2826. DoScavenging(), UpdDb in nmsscv.c,
  2827. HandleSndEntriesReq() in rplpush.c
  2828. Side Effects:
  2829. Comments:
  2830. This function changes the index on the name address table to
  2831. clustered index.
  2832. This function has grown over time. It needs to be streamlined.
  2833. --*/
  2834. {
  2835. JET_ERR JetRetStat;
  2836. DWORD OwnerId;
  2837. DWORD ActFldLen; //length of fld retrieved
  2838. VERS_NO_T VersNoDiff;
  2839. VERS_NO_T TmpNoOfEntries;
  2840. LPBYTE pStartBuff;
  2841. DWORD SaveBufLen;
  2842. BYTE EntTyp; //type of entry (unique/group/special group)
  2843. PRPL_REC_ENTRY_T pRspBuf;
  2844. JET_TABLEID TblId;
  2845. JET_SESID SesId;
  2846. PWINSTHD_TLS_T pTls;
  2847. #if NEW_OWID
  2848. DWORD RecordOwnerId;
  2849. #else
  2850. DWORD RecordOwnerId = 0;
  2851. #endif
  2852. STATUS RetStat = WINS_SUCCESS;
  2853. VERS_NO_T DefNo;
  2854. BYTE Name[NMSDB_MAX_NAM_LEN];
  2855. DWORD InitHeapSize;
  2856. DWORD MemSize;
  2857. #ifdef WINSDBG
  2858. DWORD StartTime;
  2859. DWORD EndTime;
  2860. #endif
  2861. DWORD CommitCnt = 1; //do not set to any other value
  2862. BOOL fTransCommitted;
  2863. // LPVOID pCallersAdd, pCallersCaller;
  2864. DBGENTER("NmsDbGetDataRecs\n");
  2865. // RtlGetCallersAddress(&pCallersAdd, &pCallersCaller);
  2866. // DbgPrint("Callers Address = (%x)\nCallersCaller = (%x)\n", pCallersAdd, pCallersCaller);
  2867. #ifdef WINSDBG
  2868. if (!fOnlyReplTomb)
  2869. {
  2870. struct in_addr InAddr;
  2871. if (!fUpToLimit)
  2872. {
  2873. InAddr.s_addr = htonl(pWinsAdd->Add.IPAdd);
  2874. if (MaxNoOfRecsReqd == 0)
  2875. {
  2876. DBGPRINT5(DET, "NmsDbGetDataRecs:Will retrieve records in the range (%lu %lu) to (%lu %lu) of WINS having address = (%s)\n",
  2877. MinVersNo.HighPart,
  2878. MinVersNo.LowPart,
  2879. MaxVersNo.HighPart,
  2880. MaxVersNo.LowPart,
  2881. inet_ntoa(InAddr)
  2882. );
  2883. }
  2884. else
  2885. {
  2886. DBGPRINT4(DET, "NmsDbGetDataRecs:Will retrieve a max. of %d records starting from (%lu %lu) version number of WINS having address = (%s)\n",
  2887. MaxNoOfRecsReqd,
  2888. MinVersNo.HighPart,
  2889. MinVersNo.LowPart,
  2890. inet_ntoa(InAddr)
  2891. );
  2892. }
  2893. }
  2894. else
  2895. {
  2896. if (pWinsAdd)
  2897. {
  2898. InAddr.s_addr = htonl(pWinsAdd->Add.IPAdd);
  2899. DBGPRINT3(DET, "NmsDbGetDataRecs: Will retrieve all records starting from version no (%d %d) for WINS (%s)\n", MinVersNo.HighPart, MinVersNo.LowPart, inet_ntoa(InAddr));
  2900. }
  2901. else
  2902. {
  2903. //
  2904. // fToLimit = TRUE and fOnlyReplTomb = FALSE means we
  2905. // are interested only in (active) replicas
  2906. //
  2907. DBGPRINT1(DET, "NmsDbGetDataRecs: Will retrieve all active replica records older than verify interval for WINS with owner id = (%d)\n",
  2908. pClutter->OwnerId);
  2909. }
  2910. }
  2911. }
  2912. else
  2913. {
  2914. DBGPRINT1(DET, "NmsDbGetDataRecs: Will retrieve %s replica tombstones\n", fUpToLimit ? "all" : "specified range");
  2915. }
  2916. #endif
  2917. //
  2918. // initialize the default no. that determines the size of the
  2919. // buffer to allocate in case the range specified by the Max and
  2920. // Min Vers. No args is > it
  2921. //
  2922. PERF("Move this to NmsDbInit")
  2923. WINS_ASSIGN_INT_TO_VERS_NO_M(DefNo, INIT_NO_OF_ENTRIES);
  2924. GET_TLS_M(pTls);
  2925. ASSERT(pTls != NULL);
  2926. pTls->HeapHdl = NULL; //make it NULL so that the caller can determine
  2927. //whether this function allocated a heap
  2928. //before returning (normally/abnormally)
  2929. TblId = pTls->NamAddTblId;
  2930. SesId = pTls->SesId;
  2931. /*
  2932. allocate a buffer using some rough calculations. Note: The
  2933. calculations help only if the difference between MaxVersNo and
  2934. MinVersNo is less than the predefined number (of records) we use for
  2935. allocating a buffer. if the difference is > this predefined number,
  2936. we use the predefined number since it might still suffice considering
  2937. that there may be gaps between version numbers of records falling
  2938. in the Min-Max range
  2939. */
  2940. if ((!fOnlyReplTomb) && (!fUpToLimit))
  2941. {
  2942. //
  2943. // If a max. number has been specified, use that one.
  2944. // Currently, only the scavenger thread specifies a non-zero
  2945. // value for MaxNoOfRecsReqd
  2946. //
  2947. if (MaxNoOfRecsReqd == 0)
  2948. {
  2949. VersNoDiff.QuadPart = LiSub(MaxVersNo,MinVersNo);
  2950. //
  2951. // If client is the push thread, since we will never send more
  2952. // than RPL_MAX_LIMIT_FOR_RPL records, do not allocate more
  2953. // memory than is required.
  2954. //
  2955. //
  2956. if (Client_e == WINS_E_RPLPUSH)
  2957. {
  2958. LARGE_INTEGER TmpNo;
  2959. WINS_ASSIGN_INT_TO_LI_M(TmpNo, RPL_MAX_LIMIT_FOR_RPL);
  2960. if (LiGtr(VersNoDiff, TmpNo))
  2961. {
  2962. VersNoDiff = TmpNo;
  2963. }
  2964. }
  2965. NMSNMH_INC_VERS_NO_M( VersNoDiff, VersNoDiff );
  2966. }
  2967. else
  2968. {
  2969. VersNoDiff.QuadPart = MaxNoOfRecsReqd;
  2970. }
  2971. TmpNoOfEntries = LiGtr(VersNoDiff, DefNo) ? DefNo : VersNoDiff;
  2972. }
  2973. else
  2974. {
  2975. TmpNoOfEntries = DefNo;
  2976. }
  2977. //
  2978. // Store the memory size for the records. Note: This
  2979. // does not contain the memory for the name and addresses
  2980. // (in case of a special group or a multihomed entry). The
  2981. // sizes for these will be added as we store each record.
  2982. //
  2983. MemSize = RPL_REC_ENTRY_SIZE * (TmpNoOfEntries.LowPart + 1);
  2984. *pRspBufLen = MemSize + 10000; //for good measure;
  2985. //
  2986. // We will create a heap with the above amount of memory plus a
  2987. // pad for heap overhead. We add TmpNoOfEntries.LowPart * 17
  2988. // since each record will have memory allocated for the name.
  2989. // Names in general will be 17 bytes long (we attach a NULL at the
  2990. // end when registering names).
  2991. //
  2992. if (Client_e == WINS_E_RPLPUSH)
  2993. {
  2994. InitHeapSize = (*pRspBufLen * 4) + (TmpNoOfEntries.LowPart * 17) + PAD_FOR_REC_HEAP;
  2995. }
  2996. else
  2997. {
  2998. InitHeapSize = *pRspBufLen + (TmpNoOfEntries.LowPart * 17)
  2999. + PAD_FOR_REC_HEAP;
  3000. }
  3001. //
  3002. // Create the heap
  3003. //
  3004. pTls->HeapHdl = WinsMscHeapCreate(0, InitHeapSize);
  3005. pRspBuf = WinsMscHeapAlloc(pTls->HeapHdl, MemSize);
  3006. pStartBuff = (LPBYTE)pRspBuf; //save start of buffer
  3007. SaveBufLen = MemSize; //save size of buffer
  3008. *ppRBuf = pStartBuff;
  3009. *pNoOfRecs = 0;
  3010. //
  3011. // If we are not acquiring just tombstones
  3012. //
  3013. if (!fOnlyReplTomb)
  3014. {
  3015. //
  3016. // Actually, we can call RplFindOwnerId for Scavenger thread
  3017. // We choose not to do so to avoid some overhead -- see the
  3018. // comment in the else block.
  3019. //
  3020. if (Client_e != WINS_E_NMSSCV)
  3021. {
  3022. BOOL fAllocNew = FALSE;
  3023. #if 0
  3024. BOOL fAllocNew =
  3025. (Client_e == WINS_E_WINSRPC) ? FALSE : TRUE;
  3026. //
  3027. // The following function enters a critical section.
  3028. //
  3029. // We do not want this function to allocate an
  3030. // an entry in the OwnAddTbl table for the Wins if we
  3031. // are executing in a RPC thread. We want to add
  3032. // a WINS address - Owner Id mapping in the above table
  3033. // (if not existent) only as a result of normal (as versus
  3034. // administrator initiated) actions of the WINS.
  3035. //
  3036. // NOTE: if there is no entry for the WINS address in the
  3037. // in-memory owner address table, the administrative
  3038. // action to retrieve records for a non-existent WINS will
  3039. // fail later on (as it should). Check out WinsGetDbRecs
  3040. //
  3041. #endif
  3042. try {
  3043. if (RplFindOwnerId(
  3044. pWinsAdd,
  3045. &fAllocNew,
  3046. &OwnerId,
  3047. WINSCNF_E_IGNORE_PREC,
  3048. WINSCNF_LOW_PREC
  3049. ) != WINS_SUCCESS
  3050. )
  3051. {
  3052. DBGPRINT1(ERR, "NmsDbGetDataRecs: Could not find owner id of address = (%x)\n", pWinsAdd->Add.IPAdd);
  3053. //
  3054. // The client may not look at the return value, but
  3055. // it will look at the *pNoOfRecs value and thus
  3056. // determine that there are no records.
  3057. //
  3058. return(WINS_FAILURE);
  3059. }
  3060. }
  3061. except(EXCEPTION_EXECUTE_HANDLER) {
  3062. DWORD ExcCode = GetExceptionCode();
  3063. DBGPRINT1(EXC, "NmsDbGetDataRecs: Got exception %x",
  3064. ExcCode);
  3065. WINSEVT_LOG_M(ExcCode, WINS_EVT_EXC_RETRIEVE_DATA_RECS);
  3066. return(WINS_FAILURE);
  3067. }
  3068. }
  3069. else
  3070. {
  3071. //
  3072. // Executed by scavenger thread. pClutter will not be NULL
  3073. // if we are verifying the validity of old replicas
  3074. //
  3075. if (!pClutter)
  3076. {
  3077. //
  3078. // The scavenger thread calls this function either to
  3079. // get all replica tombstones, to get records owned
  3080. // by the local WINS or verify the validity of old active
  3081. // replicas. We therefore do not need to call the
  3082. // RplFindOwnerId function (not calling it lets us avoid a
  3083. // executing a chunk of code and also saves us from entering
  3084. // a critical section)
  3085. //
  3086. OwnerId = 0;
  3087. }
  3088. else
  3089. {
  3090. //
  3091. // We are just interested in active replicas that are older
  3092. // than the verify interval
  3093. //
  3094. OwnerId = (BYTE)pClutter->OwnerId;
  3095. }
  3096. }
  3097. }
  3098. else
  3099. {
  3100. //
  3101. // Tombstones are to be retrieved.
  3102. //
  3103. // Actually we should enter a critical section prior to
  3104. // retrieving the value of NmsDbNoOfOwners since it
  3105. // can be changed by the Pull thread. We choose not to
  3106. // do so in order to save some overhead. Even if we
  3107. // get the wrong value (very low probability), we will
  3108. // know of it when we do the seek. If we get <=1 when
  3109. // it is actually more than 1, it is still ok since we
  3110. // will get the right value next time (or next to next)
  3111. //
  3112. FUTURES("Enter critical section to get NmsDbNoOfOwners. Raise priority")
  3113. FUTURES("before doing so")
  3114. if (NmsDbNoOfOwners > 1)
  3115. {
  3116. //
  3117. // We are interested in getting tombstones of
  3118. // replicas only. Tombstones on entries owned
  3119. // by the local WINS will be retrieved separately
  3120. // (every time we check whether owned entries need
  3121. // to be released or made tombstones)
  3122. //
  3123. OwnerId = 1;
  3124. #if 0
  3125. MinVersNo.LowPart = 0;
  3126. MinVersNo.HighPart = 0;
  3127. #endif
  3128. MinVersNo.QuadPart = 0;
  3129. }
  3130. else
  3131. {
  3132. DBGPRINT0(FLOW, "NmsDbGetDataRecs: This DB HAS NO REPLICAS IN IT\n");
  3133. DBGLEAVE("NmsDbGetDataRecs\n");
  3134. //
  3135. // The buffer allocated above will get deallocated
  3136. // in UpdDb (in nmsscv.c)
  3137. //
  3138. //*ppRBuf = pStartBuff;
  3139. return(WINS_SUCCESS);
  3140. }
  3141. }
  3142. /*
  3143. * start a transaction
  3144. */
  3145. CALL_M( JetBeginTransaction(SesId) );
  3146. fTransCommitted = FALSE;
  3147. try {
  3148. /*
  3149. * Use primary index now
  3150. */
  3151. CALL_M( JetSetCurrentIndex(
  3152. SesId,
  3153. TblId,
  3154. NMSDB_NAM_ADD_PRIM_INDEX_NAME
  3155. )
  3156. );
  3157. CALL_M( JetMakeKey(
  3158. SesId,
  3159. TblId,
  3160. &OwnerId,
  3161. NAM_ADD_OWNERID_SIZE,
  3162. JET_bitNewKey //since this is the first
  3163. //data value of the key
  3164. )
  3165. );
  3166. CALL_M( JetMakeKey(
  3167. SesId,
  3168. TblId,
  3169. &MinVersNo,
  3170. sizeof(VERS_NO_T),
  3171. 0 //0 for grbit since this is not the
  3172. //first component of the key
  3173. )
  3174. );
  3175. JetRetStat = JetSeek(
  3176. SesId,
  3177. TblId,
  3178. JET_bitSeekGE
  3179. );
  3180. if (JetRetStat == JET_errRecordNotFound)
  3181. {
  3182. //
  3183. // This is an error only if the function was called in the
  3184. // PUSH thread (HandleSndEntriesRsp()). If it was called
  3185. // in the Scavenger thread (DoScavenging()), it may not be an
  3186. // error. This is because when scavenging, we start with
  3187. // the lowest version number possible (1) in specifying a
  3188. // range the size of WinsCnf.ScvChunk. We them make successive
  3189. // calls for getting the next batch of records in equal
  3190. // sized ranges that occur in tandem until we reach the
  3191. // highest version number of owned records as indicated
  3192. // by NmsNmhMyMaxVersNo. It is thus very much possible that
  3193. // the ranges specified at the lower end of the list of
  3194. // ranges are devoid of records
  3195. //
  3196. if (Client_e == WINS_E_RPLPUSH)
  3197. {
  3198. DBGPRINT5(ERR, "Weird. Could not locate even one record in the range (%d %d) - (%d %d) of owner with id (%d)\n",
  3199. MinVersNo.HighPart,
  3200. MinVersNo.LowPart,
  3201. MaxVersNo.HighPart,
  3202. MaxVersNo.LowPart,
  3203. OwnerId);
  3204. WINSEVT_LOG_M(
  3205. WINS_FAILURE,
  3206. WINS_EVT_CANT_FIND_ANY_REC_IN_RANGE
  3207. );
  3208. //
  3209. // Don't free memory. It will get freed later by
  3210. // HandleSndEntriesRsp/DoScavenging. In case the caller
  3211. // is HandleSndEntriesRsp(), what will happen is that
  3212. // it will send a response with 0
  3213. // records (i.e. no records). The Pull Pnr will
  3214. // find this out and will continue to function normally
  3215. //
  3216. // The response with 0 records is doing the work of a
  3217. // negative (error) response.
  3218. //
  3219. RetStat = WINS_FAILURE;
  3220. }
  3221. #ifdef WINSDBG
  3222. else // has to be WINS_E_NMSSCV or WINS_E_WINSRPC
  3223. {
  3224. DBGPRINT0(DET, "NmsDbGetDataRecs: Did not find even one record in the db. Maybe all got deleted\n");
  3225. }
  3226. #endif
  3227. }
  3228. else //JetSeek did not return JET_errRecordNotFound.
  3229. {
  3230. UINT nLoops = 0;
  3231. CHECK("It may be better to count the number of records first and allocate")
  3232. CHECK(" a buffer big enough to store all of them (i.e. take a hit once")
  3233. CHECK(" than a small hit of an if test in every iteration. ")
  3234. //
  3235. // Do until there are no more records in the database to retrieve
  3236. //
  3237. //
  3238. // We are assured of there being at least one record since the
  3239. // JetSeek succeeded (if not for the owner we are interested in
  3240. // then for the next one).
  3241. // We can therefore safely use the do .. while() construct
  3242. //
  3243. // *NOT REALLY. It seems that JetSeek can return JET_wrnSeekNE
  3244. // even when there are no records in the db. In such a case,
  3245. // our JetRetrieveColumn will fail with a CurrencyNot there error
  3246. //
  3247. CHECK("Check with IAN JOSE")
  3248. #ifdef WINSDBG
  3249. //(void)time(&StartTime);
  3250. StartTime = GetTickCount();
  3251. #endif
  3252. do
  3253. {
  3254. //
  3255. // If the number of records has exceeded what can be stored
  3256. // in our buffer, allocate another buffer with space for DefNo (INIT_NO_OF_ENTRIES = 1000) more records
  3257. //
  3258. if (*pNoOfRecs > TmpNoOfEntries.LowPart)
  3259. {
  3260. UINT_PTR Offset = (LPBYTE)pRspBuf - pStartBuff;
  3261. //
  3262. // Not a bad place to check whether WINS has been
  3263. // terminated. Scavenger thread can take a long time
  3264. // to go through the entire db if it is large and so
  3265. // a net stop can take a long time to finish. This
  3266. // check here should speed up net stop.
  3267. //
  3268. if (Client_e == WINS_E_NMSSCV)
  3269. {
  3270. WinsMscChkTermEvt(
  3271. #ifdef WINSDBG
  3272. WINS_E_NMSSCV,
  3273. #endif
  3274. TRUE
  3275. );
  3276. }
  3277. DBGPRINT1(FLOW, "NmsDbGetDataRecs: No of Records (%d) are more than what we can store in our buffer. We will allocate a new one\n", *pNoOfRecs);
  3278. TmpNoOfEntries.QuadPart = TmpNoOfEntries.QuadPart + DefNo.QuadPart;
  3279. ASSERT(!(TmpNoOfEntries.HighPart & 0x80000000));
  3280. ASSERT(TmpNoOfEntries.LowPart < 0xFFFFFFFF);
  3281. MemSize = RPL_REC_ENTRY_SIZE * ((DWORD)TmpNoOfEntries.QuadPart + 1);
  3282. pRspBuf = HeapReAlloc(pTls->HeapHdl,
  3283. HEAP_GENERATE_EXCEPTIONS |
  3284. HEAP_ZERO_MEMORY,
  3285. pStartBuff, MemSize);
  3286. DBGPRINT1(DET, "NmsDbGetDataRecs: Doing a realloc in thd\n", pTls->ThdName);
  3287. //
  3288. // Save the start position of the new buffer
  3289. //
  3290. pStartBuff = (LPBYTE)pRspBuf;
  3291. *ppRBuf = pStartBuff;
  3292. //
  3293. // Make pRspBuf point to just past the last record
  3294. // inserted
  3295. //
  3296. pRspBuf = (PRPL_REC_ENTRY_T)(pStartBuff + Offset);
  3297. //
  3298. // Add the length we incremented *pRspBufLen by to
  3299. // the new memory size
  3300. //
  3301. *pRspBufLen = (*pRspBufLen - SaveBufLen) + MemSize;
  3302. //
  3303. // Store the new length in SaveBufLen
  3304. //
  3305. SaveBufLen = MemSize;
  3306. }
  3307. JetRetStat = JetRetrieveColumn(
  3308. SesId,
  3309. TblId,
  3310. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  3311. &RecordOwnerId,
  3312. NAM_ADD_OWNERID_SIZE,
  3313. &ActFldLen,
  3314. 0,
  3315. NULL
  3316. );
  3317. {
  3318. //
  3319. // check that we don't have some other error here
  3320. //
  3321. FUTURES("Yet another hack to workaround jet bugs = 7-11-94")
  3322. if (JetRetStat == JET_errRecordDeleted)
  3323. {
  3324. DBGPRINT2(ERR, "Jet Error: JetRetStat is (%d). Line is (%d)\n",
  3325. JetRetStat, __LINE__);
  3326. goto chkTransaction;
  3327. }
  3328. CALL_M(JetRetStat);
  3329. }
  3330. PERF("In case fOnlyReplTomb is true, retrieve the state field first")
  3331. //
  3332. // if only tombstones are required, it means that we need
  3333. // all tombstones irrespective of owner
  3334. //
  3335. if (!fOnlyReplTomb)
  3336. {
  3337. if (RecordOwnerId != OwnerId )
  3338. {
  3339. //
  3340. // We have exhausted all records for the owner. Break out
  3341. // of the loop
  3342. //
  3343. break;
  3344. }
  3345. }
  3346. //
  3347. // Retrieve the version number
  3348. //
  3349. CALL_M( JetRetrieveColumn(
  3350. SesId,
  3351. TblId,
  3352. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  3353. &(pRspBuf->VersNo),
  3354. sizeof(VERS_NO_T),
  3355. &ActFldLen,
  3356. 0,
  3357. NULL
  3358. )
  3359. );
  3360. //
  3361. // if only tombstones are required, it means that we need
  3362. // all tombstones irrespective of version number
  3363. //
  3364. if (
  3365. (!fOnlyReplTomb)
  3366. &&
  3367. (!fUpToLimit)
  3368. &&
  3369. LiGtr(pRspBuf->VersNo, MaxVersNo)
  3370. )
  3371. {
  3372. //
  3373. // We have acquired records upto MaxVersNo. Break out
  3374. // of the loop
  3375. //
  3376. break;
  3377. }
  3378. //
  3379. // Retrieve the flags byte
  3380. //
  3381. CALL_M( JetRetrieveColumn(
  3382. SesId,
  3383. TblId,
  3384. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  3385. &(pRspBuf->Flag),
  3386. sizeof(pRspBuf->Flag),
  3387. &ActFldLen,
  3388. 0,
  3389. NULL
  3390. )
  3391. );
  3392. //
  3393. // if we were asked to retrieve only dynamic records and
  3394. // this record is static, skip it.
  3395. //
  3396. if (fOnlyDynRecs && NMSDB_IS_ENTRY_STATIC_M(pRspBuf->Flag))
  3397. {
  3398. // DBGPRINT0(DET, "NmsDbGetDataRecs: Encountered a STATIC record but were asked to retrieve only dynamic records\n");
  3399. goto chkTransaction;
  3400. }
  3401. //
  3402. // retrieve the name
  3403. //
  3404. CALL_M(JetRetrieveColumn(
  3405. SesId,
  3406. TblId,
  3407. sNamAddTblRow[NAM_ADD_NAME_INDEX].Fid,
  3408. //pRspBuf->Name,
  3409. Name,
  3410. NMSDB_MAX_NAM_LEN,
  3411. &(pRspBuf->NameLen),
  3412. 0,
  3413. NULL ) );
  3414. //
  3415. // if name length is > 255, jet is returning an invalid value.
  3416. // Make the length equal to the max. length we can have for
  3417. // a netbios name. Also, log an event
  3418. //
  3419. if (pRspBuf->NameLen > WINS_MAX_NAME_SZ)
  3420. {
  3421. WINSEVT_LOG_M(pRspBuf->NameLen, WINS_EVT_NAME_TOO_LONG);
  3422. DBGPRINT1(ERR, "NmsDbGetDataRecs: Name length is too long = (%x)\n", pRspBuf->NameLen);
  3423. pRspBuf->NameLen = WINS_MAX_NS_NETBIOS_NAME_LEN;
  3424. }
  3425. //
  3426. // This macro will allocate memory and store the name in it
  3427. //
  3428. NMSDB_STORE_NAME_M(pTls, pRspBuf, Name, pRspBuf->NameLen);
  3429. //
  3430. // We need to retrieve the address field if we are in the
  3431. // PUSH thread or an RPC thread
  3432. //
  3433. if (Client_e != WINS_E_NMSSCV)
  3434. {
  3435. //
  3436. // If the record is released, go to the next record
  3437. //
  3438. if(
  3439. (Client_e == WINS_E_RPLPUSH)
  3440. &&
  3441. (NMSDB_ENTRY_REL_M(pRspBuf->Flag))
  3442. )
  3443. {
  3444. DBGPRINT0(DET,
  3445. "NmsDbGetDataRecs: ENCOUNTERED A RECORD IN THE RELEASED STATE\n");
  3446. goto chkTransaction;
  3447. }
  3448. EntTyp = (BYTE)((pRspBuf->Flag & NMSDB_BIT_ENT_TYP));
  3449. if (
  3450. (EntTyp == NMSDB_UNIQUE_ENTRY)
  3451. ||
  3452. (EntTyp == NMSDB_NORM_GRP_ENTRY)
  3453. )
  3454. {
  3455. /* It is a unique entry*/
  3456. pRspBuf->fGrp = (EntTyp == NMSDB_UNIQUE_ENTRY) ?
  3457. FALSE : TRUE;
  3458. CALL_M( JetRetrieveColumn(
  3459. SesId,
  3460. TblId,
  3461. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  3462. &pRspBuf->NodeAdd,
  3463. sizeof(COMM_ADD_T),
  3464. &ActFldLen,
  3465. 0,
  3466. NULL
  3467. )
  3468. );
  3469. }
  3470. else // it is a special group or a multihomed entry
  3471. {
  3472. //
  3473. // Even if the entry is a multihomed entry, we set the
  3474. // fGrp flag to TRUE so that the formatting function
  3475. // works properly (called by PUSH thread). The EntTyp
  3476. // will be used to decipher whether it is a multihomned
  3477. // entry or not
  3478. //
  3479. FUTURES("Remove this hacky mechanism")
  3480. pRspBuf->fGrp =
  3481. (EntTyp == NMSDB_SPEC_GRP_ENTRY) ? TRUE : FALSE;
  3482. /*
  3483. * get member addresses.
  3484. *
  3485. * If we are in an RPC thread, we want to get the members
  3486. * even if they are expired. We can do that by
  3487. * passing a TRUE value for the STATIC flag parameter.
  3488. */
  3489. StoreGrpMems(
  3490. pTls,
  3491. Client_e,
  3492. pRspBuf->pName,
  3493. ThdPrLvl,
  3494. SesId,
  3495. TblId,
  3496. (WINS_E_WINSRPC == Client_e ? TRUE
  3497. : NMSDB_IS_ENTRY_STATIC_M(pRspBuf->Flag)),
  3498. pRspBuf
  3499. );
  3500. //
  3501. // if the record is active but has no members,
  3502. // don't send it. It is possible that all
  3503. // members of the group expired after the last scavenging
  3504. // cycle. This record will be marked RELEASED at the next
  3505. // scavenging cycle.
  3506. // For now ignore the record
  3507. //
  3508. if (
  3509. (pRspBuf->NoOfAdds == 0)
  3510. &&
  3511. (NMSDB_ENTRY_ACT_M(pRspBuf->Flag))
  3512. )
  3513. {
  3514. if (Client_e == WINS_E_RPLPUSH)
  3515. {
  3516. DBGPRINT2(FLOW, "NmsDbGetDataRecs: Active Group (Version # %d %d) has no members. So it is not being replicated\n", pRspBuf->VersNo.HighPart, pRspBuf->VersNo.LowPart/*pRspBuf->Name*/);
  3517. goto chkTransaction;
  3518. }
  3519. else
  3520. {
  3521. //
  3522. //Must be an RPC thread.
  3523. //Change the state to released so that the
  3524. //record shows up as released when displayed
  3525. //
  3526. NMSDB_CLR_STATE_M(pRspBuf->Flag);
  3527. NMSDB_SET_STATE_M(pRspBuf->Flag, NMSDB_E_RELEASED);
  3528. }
  3529. }
  3530. } // end of else
  3531. //
  3532. // Adjust the size to be passed to the push thread
  3533. //
  3534. if (Client_e == WINS_E_RPLPUSH)
  3535. {
  3536. *pRspBufLen += pRspBuf->NameLen;
  3537. if ((EntTyp == NMSDB_MULTIHOMED_ENTRY) ||
  3538. (EntTyp == NMSDB_SPEC_GRP_ENTRY)
  3539. )
  3540. {
  3541. *pRspBufLen +=
  3542. (pRspBuf->NoOfAdds * sizeof(COMM_ADD_T) * 2);
  3543. }
  3544. }
  3545. //
  3546. // If client is the RPC thread, retrieve the timestamp
  3547. //
  3548. if (Client_e == WINS_E_WINSRPC)
  3549. {
  3550. //
  3551. // get the timestamp field
  3552. //
  3553. CALL_M( JetRetrieveColumn(
  3554. SesId,
  3555. TblId,
  3556. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  3557. &(pRspBuf->TimeStamp),
  3558. sizeof(pRspBuf->TimeStamp),
  3559. &ActFldLen,
  3560. 0,
  3561. NULL
  3562. )
  3563. );
  3564. if (!fOnlyDynRecs && NMSDB_IS_ENTRY_STATIC_M(pRspBuf->Flag)
  3565. && (OwnerId == NMSDB_LOCAL_OWNER_ID) && NMSDB_ENTRY_ACT_M(pRspBuf->Flag))
  3566. {
  3567. pRspBuf->TimeStamp = MAXLONG;
  3568. }
  3569. }
  3570. }
  3571. else //client is the scavenger thread
  3572. {
  3573. //
  3574. // If only tombstones are required and this record is not
  3575. // a tombstone, go to the next record
  3576. //
  3577. if (fOnlyReplTomb && !NMSDB_ENTRY_TOMB_M(pRspBuf->Flag))
  3578. {
  3579. goto chkTransaction;
  3580. }
  3581. //
  3582. // pClutter will not be NULL if this function was called
  3583. // by the scavenger thread to either retrieve replica
  3584. // tombstones or to retrieve replicas for consistency
  3585. // checking
  3586. //
  3587. if (pClutter && !fOnlyReplTomb)
  3588. {
  3589. //
  3590. // Want all replicas
  3591. // for consistency checking
  3592. //
  3593. if ( !pClutter->fAll)
  3594. {
  3595. //
  3596. // just interested in active records
  3597. //
  3598. if (!NMSDB_ENTRY_ACT_M(pRspBuf->Flag))
  3599. {
  3600. goto chkTransaction;
  3601. }
  3602. }
  3603. }
  3604. //
  3605. // get the timestamp field
  3606. //
  3607. CALL_M( JetRetrieveColumn(
  3608. SesId,
  3609. TblId,
  3610. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  3611. &(pRspBuf->TimeStamp),
  3612. sizeof(pRspBuf->TimeStamp),
  3613. &ActFldLen,
  3614. 0,
  3615. NULL
  3616. )
  3617. );
  3618. if (pClutter)
  3619. {
  3620. //
  3621. // if we are retrieving clutter, check the time stamp
  3622. // unless this is a static record
  3623. //
  3624. if( !fOnlyReplTomb)
  3625. {
  3626. FUTURES("We need to skip this for owned static records only, not for all")
  3627. // if (!NMSDB_IS_ENTRY_STATIC_M(pRspBuf->Flag))
  3628. {
  3629. //
  3630. // if this record is not old enough, we are not interested
  3631. //
  3632. if (
  3633. pClutter->Age &&
  3634. (pRspBuf->TimeStamp > (DWORD)pClutter->CurrentTime)
  3635. )
  3636. {
  3637. goto chkTransaction;
  3638. }
  3639. }
  3640. }
  3641. else
  3642. {
  3643. //
  3644. // We want replica tombstones.
  3645. //
  3646. if (NMSDB_ENTRY_TOMB_M(pRspBuf->Flag))
  3647. {
  3648. if (pClutter->CurrentTime < (time_t)pRspBuf->TimeStamp)
  3649. {
  3650. goto chkTransaction;
  3651. }
  3652. }
  3653. }
  3654. }
  3655. } // end of else (Client is the scavenger thread)
  3656. //
  3657. // increment the counter and the pointer to past the last record.
  3658. //
  3659. pRspBuf = (PRPL_REC_ENTRY_T)((LPBYTE)pRspBuf + RPL_REC_ENTRY_SIZE);
  3660. (*pNoOfRecs)++;
  3661. if (Client_e == WINS_E_RPLPUSH)
  3662. {
  3663. if (*pNoOfRecs == RPL_MAX_LIMIT_FOR_RPL)
  3664. {
  3665. break;
  3666. }
  3667. }
  3668. //
  3669. // if we have retrieved the max. number asked for, break out of
  3670. // the loop
  3671. //
  3672. if ((MaxNoOfRecsReqd > 0) && (*pNoOfRecs >= MaxNoOfRecsReqd))
  3673. {
  3674. break;
  3675. }
  3676. chkTransaction:
  3677. //
  3678. // If this is the scavenger thread, let us give the version store
  3679. // a breather after a certain number of records have been retrieved
  3680. //
  3681. if (nLoops/CommitCnt >= MAX_RECS_BEFORE_COMMIT)
  3682. {
  3683. //
  3684. // Let us commit the transaction to free up the version store
  3685. //
  3686. CALL_M(
  3687. JetCommitTransaction(SesId, JET_bitCommitFlush)
  3688. );
  3689. fTransCommitted = TRUE;
  3690. CommitCnt++;
  3691. CALL_M( JetBeginTransaction(SesId) );
  3692. fTransCommitted = FALSE;
  3693. }
  3694. nLoops++;
  3695. } while(JetMove(SesId, TblId, JET_MoveNext, 0) >= 0);
  3696. #ifdef WINSDBG
  3697. EndTime = GetTickCount();
  3698. DBGPRINT2(TM, "NmsDbGetDataRecs: Retrieved %d records in %d secs\n",
  3699. *pNoOfRecs, StartTime - EndTime);
  3700. #endif
  3701. } // end of else
  3702. } // end of try {..}
  3703. finally {
  3704. if (AbnormalTermination())
  3705. {
  3706. DWORD EvtCode;
  3707. DBGPRINT0(ERR,
  3708. "NmsDbGetDataRecs: Terminating abnormally\n");
  3709. if (Client_e == WINS_E_WINSRPC)
  3710. {
  3711. EvtCode = WINS_EVT_RPC_EXC;
  3712. }
  3713. else
  3714. {
  3715. EvtCode = (Client_e == WINS_E_RPLPUSH) ?
  3716. WINS_EVT_RPLPUSH_EXC :
  3717. WINS_EVT_SCV_EXC;
  3718. }
  3719. WINSEVT_LOG_M(WINS_FAILURE, EvtCode);
  3720. RetStat = WINS_FAILURE;
  3721. }
  3722. //*ppRBuf = pStartBuff;
  3723. DBGPRINT1(FLOW, "NmsDbGetDataRecs:Retrieved %d records\n",
  3724. *pNoOfRecs);
  3725. //
  3726. // If the no of records retrieved is 0, log an informational
  3727. // message. The reason for 0 records being retrieved could
  3728. // be that all records are released
  3729. //
  3730. if (*pNoOfRecs == 0)
  3731. {
  3732. WINSEVT_STRS_T EvtStrs;
  3733. EvtStrs.NoOfStrs = 1;
  3734. if (Client_e == WINS_E_RPLPUSH)
  3735. {
  3736. //EvtStrs.pStr[0] = TEXT("Replicator Push");
  3737. if (WinsCnf.LogDetailedEvts > 0)
  3738. {
  3739. WinsEvtLogDetEvt(TRUE,
  3740. WINS_EVT_NO_RPL_RECS_RETRIEVED, NULL, __LINE__, "ddddd", pWinsAdd != NULL ? pWinsAdd->Add.IPAdd : 0, MinVersNo.LowPart, MinVersNo.HighPart, MaxVersNo.LowPart, MaxVersNo.HighPart);
  3741. //WINSEVT_LOG_INFO_STR_D_M( WINS_EVT_NO_RPL_RECS_RETRIEVED, &EvtStrs );
  3742. }
  3743. }
  3744. else
  3745. {
  3746. // Per bug#339152 remove this.
  3747. //EvtStrs.pStr[0] = (Client_e == WINS_E_NMSSCV) ?TEXT("Scavenging") : TEXT("Client");
  3748. //WINSEVT_LOG_INFO_STR_D_M( WINS_EVT_NO_RECS_RETRIEVED, &EvtStrs );
  3749. }
  3750. }
  3751. //
  3752. // We are done. Let us commit the transaction
  3753. //
  3754. if (!fTransCommitted)
  3755. {
  3756. JET_ERR JetRetStat;
  3757. JetRetStat = JetCommitTransaction(SesId, JET_bitCommitFlush);
  3758. if (RetStat != WINS_FAILURE)
  3759. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  3760. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  3761. CALL_M(JetRetStat);
  3762. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  3763. }
  3764. }
  3765. DBGLEAVE("NmsDbGetDataRecs\n");
  3766. return(RetStat);
  3767. }
  3768. VOID
  3769. StoreGrpMems(
  3770. IN PWINSTHD_TLS_T pTls,
  3771. IN WINS_CLIENT_E Client_e,
  3772. IN LPBYTE pName,
  3773. IN INT ThdPrLvl,
  3774. IN JET_SESID SesId,
  3775. IN JET_TABLEID TblId,
  3776. IN BOOL fStatic,
  3777. IN PRPL_REC_ENTRY_T pRspInfo
  3778. )
  3779. /*++
  3780. Routine Description:
  3781. This function retrieves all the addresses in the group record
  3782. and stores them in the data structure passed to it
  3783. Arguments:
  3784. Client_e - Client (indicates the thread) calling this function
  3785. ThdPrLvl - The normal priority level of thread (is looked at only
  3786. if the client is WINS_E_NMSSCV (scavenger thread)
  3787. SesId - Id of this thread's session with the db
  3788. TblId - Id of the name-address table
  3789. fStatic - indicates whether the entry is STATIC
  3790. RspInfo - Contains members of a special group (after this function
  3791. is done)
  3792. Externals Used:
  3793. None
  3794. Return Value:
  3795. None
  3796. Error Handling:
  3797. Called by:
  3798. NmsDbGetDataRecs
  3799. Side Effects:
  3800. Comments:
  3801. This function assumes that a heap has been created for use by this
  3802. thread. Currently, this function is called only by NmsDbGetDataRecs
  3803. --*/
  3804. {
  3805. BOOL fIsMem;
  3806. NMSDB_ROW_INFO_T RowInfo;
  3807. NMSDB_STAT_INFO_T StatusInfo;
  3808. DWORD i; //for loop counter
  3809. DWORD n = 0; //indexes NodeAdd array
  3810. PNMSDB_WINS_STATE_E pWinsState_e;
  3811. PCOMM_ADD_T pWinsAdd;
  3812. PVERS_NO_T pStartVersNo;
  3813. PWINS_UID_T pUid;
  3814. //
  3815. // init to 0
  3816. //
  3817. RowInfo.NodeAdds.Mem[0].Add.Add.IPAdd = 0;
  3818. RowInfo.pName = pName;
  3819. //
  3820. // Get and store the current time.
  3821. //
  3822. (void)time(&RowInfo.TimeStamp);
  3823. //
  3824. // get all active group members
  3825. //
  3826. GetGrpMem(
  3827. SesId,
  3828. TblId,
  3829. &RowInfo,
  3830. RowInfo.TimeStamp,
  3831. &StatusInfo,
  3832. fStatic,
  3833. &fIsMem
  3834. );
  3835. pRspInfo->NoOfAdds = StatusInfo.NodeAdds.NoOfMems;
  3836. //
  3837. // If we are in the scavenger thread, raise our priority level to
  3838. // normal before entering the critical section.
  3839. //
  3840. if (Client_e == WINS_E_NMSSCV)
  3841. {
  3842. WinsMscSetThreadPriority(
  3843. WinsThdPool.ScvThds[0].ThdHdl,
  3844. THREAD_PRIORITY_NORMAL
  3845. );
  3846. }
  3847. if (pRspInfo->NoOfAdds > 0)
  3848. {
  3849. //
  3850. // Allocate memory to store group members
  3851. //
  3852. pRspInfo->pNodeAdd = WinsMscHeapAlloc(
  3853. pTls->HeapHdl,
  3854. StatusInfo.NodeAdds.NoOfMems *
  3855. sizeof(COMM_ADD_T) * 2
  3856. );
  3857. }
  3858. else
  3859. {
  3860. pRspInfo->pNodeAdd = NULL;
  3861. }
  3862. //
  3863. // This critical section guards us against simultaenous updates
  3864. // to the NmsDbOwnAddTbl (accessed by RPL_FIND_ADD_BY_OWNER_ID_M
  3865. // macro) by the PULL thread
  3866. //
  3867. EnterCriticalSection(&NmsDbOwnAddTblCrtSec);
  3868. try {
  3869. //
  3870. // Store the group members
  3871. //
  3872. for (i=0; i<StatusInfo.NodeAdds.NoOfMems; i++)
  3873. {
  3874. RPL_FIND_ADD_BY_OWNER_ID_M(
  3875. StatusInfo.NodeAdds.Mem[i].OwnerId,
  3876. pWinsAdd,
  3877. pWinsState_e,
  3878. pStartVersNo
  3879. );
  3880. //
  3881. // First address is the address of the owner WINS
  3882. // Second address is the address of the member
  3883. //
  3884. *(pRspInfo->pNodeAdd + n) = *pWinsAdd;
  3885. n++;
  3886. *(pRspInfo->pNodeAdd + n) = StatusInfo.NodeAdds.Mem[i].Add;
  3887. n++;
  3888. }
  3889. }
  3890. except(EXCEPTION_EXECUTE_HANDLER) {
  3891. DWORD ExcCode = GetExceptionCode();
  3892. DBGPRINT1(EXC, "StoreGrpMems. Got Exception %x", ExcCode);
  3893. WINSEVT_LOG_M(ExcCode, WINS_EVT_GRP_MEM_PROC_EXC);
  3894. }
  3895. LeaveCriticalSection(&NmsDbOwnAddTblCrtSec);
  3896. if (Client_e == WINS_E_NMSSCV)
  3897. {
  3898. //
  3899. // revert to old priority level
  3900. //
  3901. WinsMscSetThreadPriority(
  3902. WinsThdPool.ScvThds[0].ThdHdl,
  3903. ThdPrLvl
  3904. );
  3905. }
  3906. return;
  3907. }
  3908. STATUS
  3909. CreateTbl(
  3910. JET_DBID DbId,
  3911. JET_SESID SesId,
  3912. JET_TABLEID *pTblId,
  3913. NMSDB_TBL_NAM_E TblNam_e //enumerator value for table to create
  3914. )
  3915. /*++
  3916. Routine Description:
  3917. This function creates a table.
  3918. Arguments:
  3919. DbId - Database Id.
  3920. SesId - Session Id.
  3921. pTblId - Id of the table created
  3922. TblNm_e - Identifies the table to create
  3923. Externals Used:
  3924. None
  3925. Return Value:
  3926. Success status codes -- WINS_SUCCESS
  3927. Error status codes -- WINS_FAILURE
  3928. Error Handling:
  3929. Called by:
  3930. NmsDbInit
  3931. Side Effects:
  3932. Comments:
  3933. None
  3934. --*/
  3935. {
  3936. #define LANGID 0x0409
  3937. #define CP 1252
  3938. BYTE TmpCol[MAX_FIXED_FLD_LEN];
  3939. DWORD FldNo; /*counter for fields */
  3940. JET_TABLEID TblId; /*id of table created*/
  3941. JET_COLUMNDEF columndef;
  3942. //
  3943. // Init fields of columndef that do not change between additions of
  3944. // columns
  3945. //
  3946. columndef.cbStruct = sizeof(columndef);
  3947. columndef.columnid = 0;
  3948. columndef.cp = CP;
  3949. columndef.langid = LANGID;
  3950. columndef.cbMax = 0;
  3951. columndef.grbit = 0;
  3952. /*
  3953. Switch on Table Name
  3954. */
  3955. switch(TblNam_e)
  3956. {
  3957. /*
  3958. The Name to Address Mapping table needs to be created
  3959. */
  3960. case(NMSDB_E_NAM_ADD_TBL_NM):
  3961. /*
  3962. Create the Nam IP address mapping table
  3963. */
  3964. CALL_M( JetCreateTable(
  3965. SesId,
  3966. DbId,
  3967. NMSDB_NAM_ADD_TBL_NM,
  3968. NMSDB_NAM_ADD_TBL_PGS,
  3969. NMSDB_NAM_ADD_TBL_DENSITY,
  3970. &TblId
  3971. )
  3972. );
  3973. NOTE("DDL such as AddColumn and CreateIndex on a table in shared access mode")
  3974. NOTE("will return an error unless we are at transaction level 0 (i.e no Begin")
  3975. NOTE("transaction). If done on a table in exclusive mode, it is ok -- Ian ")
  3976. NOTE("10/16/93")
  3977. //
  3978. // In order to open the table with shared access, we need
  3979. // to close the handle returned from CreateTable (this
  3980. // one has deny read access flag set) and open the
  3981. // table for shared access
  3982. //
  3983. CALL_M(JetCloseTable(
  3984. SesId,
  3985. TblId
  3986. )
  3987. );
  3988. CALL_M(JetOpenTable(
  3989. SesId,
  3990. DbId,
  3991. NMSDB_NAM_ADD_TBL_NM,
  3992. NULL, /*ptr to parameter list; should be
  3993. *non-NULL if a query is being
  3994. *opened*/
  3995. 0, /*Length of above parameter list*/
  3996. 0, //shared access (no bit set)
  3997. &TblId
  3998. )
  3999. );
  4000. *pTblId = TblId;
  4001. /*
  4002. Add columns
  4003. */
  4004. for ( FldNo=0 ; FldNo < NO_COLS_NAM_ADD_TBL ; ++FldNo )
  4005. {
  4006. columndef.coltyp = sNamAddTblRow[FldNo].FldTyp;
  4007. CALL_M( JetAddColumn (
  4008. SesId, // user
  4009. TblId, // table id
  4010. sNamAddTblRow[FldNo].pName, // fld name
  4011. &columndef, // columndef
  4012. NULL, // default value
  4013. 0, // default value length
  4014. &sNamAddTblRow[FldNo].Fid // field id
  4015. )
  4016. );
  4017. }
  4018. /*
  4019. * Create clustered index (in ascending order) on the name field.
  4020. *
  4021. * In NT5.0 (Jet600), we do not create the cluster key. The
  4022. * primary index is the one on which Jet clusters. The primary
  4023. * key should be smaller, because in Jet600 Jet uses primary key
  4024. * bookmarks, meaning that the bookmark length will be entirely
  4025. * dependent on the length of the primary key.Jonathan Liem (1/7/97)
  4026. *
  4027. * Rule for creating index:
  4028. *
  4029. * The index key contains a sequence of concatenated
  4030. * column names, in order of key significance, each
  4031. * of which is null terminated and prefixed with either
  4032. * '+' or '-', indicating ascending or descending. The
  4033. * entire sequence must be double null terminated.
  4034. *
  4035. */
  4036. sprintf( TmpCol, "+%s",
  4037. sNamAddTblRow[NAM_ADD_NAME_INDEX].pName );
  4038. TmpCol[ 2 +
  4039. strlen( sNamAddTblRow[NAM_ADD_NAME_INDEX].pName )
  4040. ] = '\0';
  4041. if (DynLoadJetVersion >= DYN_LOAD_JET_600) {
  4042. CALL_M(
  4043. JetCreateIndex(
  4044. SesId,
  4045. TblId,
  4046. NMSDB_NAM_ADD_CLUST_INDEX_NAME, // name of index
  4047. JET_bitIndexPrimary | JET_bitIndexUnique | JET_bitIndexDisallowNull,
  4048. TmpCol,
  4049. 3 +
  4050. strlen( sNamAddTblRow[NAM_ADD_NAME_INDEX].pName),
  4051. NMSDB_NAM_ADD_CLUST_INDEX_DENSITY /*% space on each
  4052. page to be used*/
  4053. )
  4054. );
  4055. } else {
  4056. CALL_M(
  4057. JetCreateIndex(
  4058. SesId,
  4059. TblId,
  4060. NMSDB_NAM_ADD_CLUST_INDEX_NAME, // name of index
  4061. JET_bitIndexClustered | JET_bitIndexUnique | JET_bitIndexDisallowNull,
  4062. TmpCol,
  4063. 3 +
  4064. strlen( sNamAddTblRow[NAM_ADD_NAME_INDEX].pName),
  4065. NMSDB_NAM_ADD_CLUST_INDEX_DENSITY /*% space on each
  4066. page to be used*/
  4067. )
  4068. );
  4069. }
  4070. CHECK("What exactly does DENSITY argument do for us")
  4071. /*
  4072. * Create Primary Index using the ownerid and the version cols
  4073. */
  4074. sprintf( TmpCol, "+%s",
  4075. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].pName
  4076. );
  4077. sprintf(
  4078. &TmpCol[2 + strlen(sNamAddTblRow[NAM_ADD_OWNERID_INDEX].pName)],
  4079. "+%s", sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].pName
  4080. );
  4081. TmpCol[ 4 +
  4082. strlen( sNamAddTblRow[NAM_ADD_OWNERID_INDEX].pName ) +
  4083. strlen(sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].pName)
  4084. ] = '\0';
  4085. if (DynLoadJetVersion >= DYN_LOAD_JET_600) {
  4086. CALL_M( JetCreateIndex(
  4087. SesId,
  4088. TblId,
  4089. NMSDB_NAM_ADD_PRIM_INDEX_NAME, // name of index
  4090. JET_bitIndexUnique, //in jet600 dont need primary index.
  4091. TmpCol,
  4092. 5 +
  4093. strlen( sNamAddTblRow[NAM_ADD_OWNERID_INDEX].pName) +
  4094. strlen( sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].pName),
  4095. NMSDB_NAM_ADD_PRIM_INDEX_DENSITY /*% space on each
  4096. page to be used*/
  4097. )
  4098. );
  4099. } else {
  4100. CALL_M( JetCreateIndex(
  4101. SesId,
  4102. TblId,
  4103. NMSDB_NAM_ADD_PRIM_INDEX_NAME, // name of index
  4104. JET_bitIndexPrimary, //primary index is unique by def.
  4105. TmpCol,
  4106. 5 +
  4107. strlen( sNamAddTblRow[NAM_ADD_OWNERID_INDEX].pName) +
  4108. strlen( sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].pName),
  4109. NMSDB_NAM_ADD_PRIM_INDEX_DENSITY /*% space on each
  4110. page to be used*/
  4111. )
  4112. );
  4113. }
  4114. break;
  4115. case(NMSDB_E_OWN_ADD_TBL_NM):
  4116. /*
  4117. Create the Owner address mapping table
  4118. */
  4119. CALL_M( JetCreateTable(
  4120. SesId,
  4121. DbId,
  4122. NMSDB_OWN_ADD_TBL_NM,
  4123. NMSDB_OWN_ADD_TBL_PGS,
  4124. NMSDB_OWN_ADD_TBL_DENSITY,
  4125. &TblId
  4126. )
  4127. );
  4128. //
  4129. // In order to open the table with shared access, we need
  4130. // to close the handle returned from CreateTable (this
  4131. // one has deny read access flag set) and open the
  4132. // table for shared access
  4133. //
  4134. CALL_M(JetCloseTable(
  4135. SesId,
  4136. TblId
  4137. )
  4138. );
  4139. CALL_M(JetOpenTable(
  4140. SesId,
  4141. DbId,
  4142. NMSDB_OWN_ADD_TBL_NM,
  4143. NULL, /*ptr to parameter list; should be
  4144. *non-NULL if a query is being
  4145. *opened*/
  4146. 0, /*Length of above parameter list*/
  4147. 0, //shared access (no bit set)
  4148. &TblId
  4149. )
  4150. );
  4151. *pTblId = TblId;
  4152. /*
  4153. Add columns
  4154. */
  4155. for ( FldNo=0 ; FldNo < NO_COLS_OWN_ADD_TBL ; ++FldNo )
  4156. {
  4157. JET_COLUMNDEF columndef;
  4158. columndef.cbStruct = sizeof(columndef);
  4159. columndef.columnid = 0;
  4160. columndef.coltyp = sOwnAddTblRow[FldNo].FldTyp;
  4161. columndef.cp = 1252;
  4162. columndef.langid = 0x0409;
  4163. columndef.cbMax = 0;
  4164. columndef.grbit = 0;
  4165. CALL_M( JetAddColumn(
  4166. SesId, // user
  4167. TblId, // table id
  4168. sOwnAddTblRow[FldNo].pName, // fld name
  4169. &columndef, // columndef
  4170. NULL, // default value
  4171. 0, // default value lenght
  4172. &sOwnAddTblRow[FldNo].Fid // field id.
  4173. )
  4174. );
  4175. } //end of for loop
  4176. /*
  4177. Insertions into this table will be in the order of increasing
  4178. owner ids. with the owner id. 0 always referring to the local
  4179. WINS.
  4180. The state of an entry in the table can be active or down or
  4181. deleted.
  4182. As an aside (this comment is out of context here, but anyway..)
  4183. deleted entries are removed at boot time. Also, all records
  4184. owned by the WINS of a deleted entry are removed from the
  4185. Name Address table at boot time.i This functionality is a
  4186. future enhancement
  4187. */
  4188. /*
  4189. * Create clustered index
  4190. */
  4191. sprintf( TmpCol, "+%s",
  4192. sOwnAddTblRow[OWN_ADD_OWNERID_INDEX].pName
  4193. );
  4194. TmpCol[ 2 +
  4195. strlen( sOwnAddTblRow[OWN_ADD_OWNERID_INDEX].pName )] = '\0';
  4196. if (DynLoadJetVersion >= DYN_LOAD_JET_600) {
  4197. CALL_M( JetCreateIndex(
  4198. SesId,
  4199. TblId,
  4200. NMSDB_OWN_ADD_CLUST_INDEX_NAME, // name of index
  4201. JET_bitIndexPrimary | JET_bitIndexUnique,
  4202. TmpCol,
  4203. 3 +
  4204. strlen( sOwnAddTblRow[OWN_ADD_OWNERID_INDEX].pName),
  4205. NMSDB_OWN_ADD_CLUST_INDEX_DENSITY /*% space on each
  4206. page to alloc
  4207. */
  4208. )
  4209. );
  4210. } else{
  4211. CALL_M( JetCreateIndex(
  4212. SesId,
  4213. TblId,
  4214. NMSDB_OWN_ADD_CLUST_INDEX_NAME, // name of index
  4215. JET_bitIndexClustered | JET_bitIndexUnique,
  4216. TmpCol,
  4217. 3 +
  4218. strlen( sOwnAddTblRow[OWN_ADD_OWNERID_INDEX].pName),
  4219. NMSDB_OWN_ADD_CLUST_INDEX_DENSITY /*% space on each
  4220. page to alloc
  4221. */
  4222. )
  4223. );
  4224. }
  4225. CHECK("Do we need to set this")
  4226. /*
  4227. * Set the clustered index as the current index
  4228. */
  4229. CALL_M(
  4230. JetSetCurrentIndex( SesId,
  4231. TblId,
  4232. NMSDB_OWN_ADD_CLUST_INDEX_NAME
  4233. )
  4234. );
  4235. break;
  4236. default:
  4237. DBGPRINT1(ERR, "CreateTbl: Invalid Tbl id (%d)\n",
  4238. TblNam_e);
  4239. WINSEVT_LOG_M(WINS_FATAL_ERR, WINS_EVT_SFT_ERR);
  4240. return(WINS_FAILURE);
  4241. break;
  4242. } //end of switch
  4243. return(WINS_SUCCESS);
  4244. }
  4245. STATUS
  4246. InitColInfo (
  4247. JET_SESID SesId,
  4248. JET_TABLEID TblId,
  4249. NMSDB_TBL_NAM_E TblNam_e
  4250. )
  4251. /*++
  4252. Routine Description:
  4253. This function is called to get information about the different
  4254. columns of a table
  4255. Arguments:
  4256. SesId - Session Id
  4257. TblId - Id. of open table
  4258. TblNam_e - Indicator or table
  4259. Externals Used:
  4260. None
  4261. Return Value:
  4262. Success status codes -- WINS_SUCCESS
  4263. Error status codes -- WINS_FAILURE
  4264. Error Handling:
  4265. Called by:
  4266. NmsDbInit (Main Thread of the process)
  4267. Side Effects:
  4268. Comments:
  4269. None
  4270. --*/
  4271. {
  4272. JET_COLUMNDEF ColumnDef;
  4273. PFLD_T pRow = NULL;
  4274. DWORD FldNo = 0;
  4275. DWORD NoOfCols = 0;
  4276. STATUS RetStat = WINS_SUCCESS;
  4277. /*
  4278. Switch on Table Name
  4279. */
  4280. switch(TblNam_e)
  4281. {
  4282. /*
  4283. The Name to Address Mapping table needs to be created
  4284. */
  4285. case(NMSDB_E_NAM_ADD_TBL_NM):
  4286. pRow = sNamAddTblRow;
  4287. NoOfCols = NO_COLS_NAM_ADD_TBL;
  4288. break;
  4289. case(NMSDB_E_OWN_ADD_TBL_NM):
  4290. pRow = sOwnAddTblRow;
  4291. NoOfCols = NO_COLS_OWN_ADD_TBL;
  4292. break;
  4293. default:
  4294. DBGPRINT1(ERR, "InitColInfo: Invalid Tbl id (%d)\n",
  4295. TblNam_e);
  4296. WINSEVT_LOG_M(WINS_FATAL_ERR, WINS_EVT_SFT_ERR);
  4297. RetStat = WINS_FATAL_ERR;
  4298. break;
  4299. }
  4300. /*
  4301. Get info about columns
  4302. */
  4303. for ( FldNo=0 ; FldNo < NoOfCols; ++FldNo )
  4304. {
  4305. CALL_M( JetGetTableColumnInfo (
  4306. SesId, // user session
  4307. TblId, // table id
  4308. pRow[FldNo].pName, // fld name
  4309. &ColumnDef, // columndef
  4310. sizeof(ColumnDef),
  4311. JET_ColInfo //info level 0
  4312. )
  4313. );
  4314. pRow[FldNo].Fid = ColumnDef.columnid; // field id
  4315. }
  4316. return(RetStat);
  4317. }
  4318. STATUS
  4319. ReadOwnAddTbl(
  4320. JET_SESID SesId,
  4321. JET_DBID DbId,
  4322. JET_TABLEID TblId
  4323. )
  4324. /*++
  4325. Routine Description:
  4326. This function is called to read all the entries of the Owner - Address
  4327. mapping table into the in-memory data structure
  4328. It is called at init time
  4329. Arguments:
  4330. SesId
  4331. DbId
  4332. TblId
  4333. Externals Used:
  4334. NmsDbOwnAddTbl
  4335. Return Value:
  4336. Success status codes -- WINS_SUCCESS
  4337. Error status codes -- WINS_FAILURE
  4338. Error Handling:
  4339. Called by:
  4340. NmsDbInit()
  4341. Side Effects:
  4342. Comments:
  4343. No need to start a transaction in this since it is called only
  4344. by NmsDbInit (at initialization time)
  4345. --*/
  4346. {
  4347. PNMSDB_ADD_STATE_T pOwnAddTbl = NULL;
  4348. DWORD i, n;
  4349. LONG ActFldLen;
  4350. DWORD cOwners = 0;
  4351. JET_ERR JetRetStat;
  4352. #if NEW_OWID
  4353. DWORD OwnerId;
  4354. #else
  4355. DWORD OwnerId = 0;
  4356. #endif
  4357. DWORD LastOwnerId = 0;
  4358. BOOL fLogged = FALSE;
  4359. STATUS RetStat = WINS_SUCCESS;
  4360. DBGENTER("ReadOwnAddTbl\n");
  4361. pOwnAddTbl = pNmsDbOwnAddTbl;
  4362. /*
  4363. * Setting the index will move the database cursor to the first record
  4364. *in the table.
  4365. */
  4366. CALL_M(
  4367. JetSetCurrentIndex(
  4368. SesId,
  4369. TblId,
  4370. NMSDB_OWN_ADD_CLUST_INDEX_NAME
  4371. )
  4372. );
  4373. /*
  4374. * Loop until the end of the table is reached. We are retrieving
  4375. * records in the order of increasing owner ids.
  4376. */
  4377. do
  4378. {
  4379. //
  4380. // retrieve the OwnerId column
  4381. //
  4382. JetRetStat =
  4383. JetRetrieveColumn(
  4384. SesId,
  4385. TblId,
  4386. sOwnAddTblRow[OWN_ADD_OWNERID_INDEX].Fid,
  4387. &OwnerId,
  4388. OWN_ADD_OWNERID_SIZE,
  4389. &ActFldLen,
  4390. 0,
  4391. NULL
  4392. );
  4393. if (JetRetStat == JET_errNoCurrentRecord)
  4394. {
  4395. //
  4396. // If this is not the first iteration of the loop, then
  4397. // there is something seriously wrong. Log an error and
  4398. // raise exception
  4399. //
  4400. if (NmsDbNoOfOwners != 0)
  4401. {
  4402. DBGPRINT0(EXC,
  4403. "There is no current record to retrieve from\n");
  4404. WINSEVT_LOG_M(JetRetStat, WINS_EVT_SFT_ERR);
  4405. WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
  4406. }
  4407. else
  4408. {
  4409. DBGPRINT0(ERR,
  4410. "ReadOwnAddTbl: There are no records in this table.");
  4411. WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_NO_RECS_IN_OWN_ADD_TBL);
  4412. }
  4413. break; //break out of the loop
  4414. }
  4415. else
  4416. {
  4417. CALL_M(JetRetStat);
  4418. }
  4419. // the (OwnerId<->Addr) table is not large enough to contain a slot at index OwnerId.
  4420. // the table has to be enlarged in order to cover this index.
  4421. if (NmsDbTotNoOfSlots <= OwnerId)
  4422. {
  4423. DWORD newNoOfSlots = max(NmsDbTotNoOfSlots*2, OwnerId+1);
  4424. WINSMSC_REALLOC_M(
  4425. sizeof(NMSDB_ADD_STATE_T) * newNoOfSlots,
  4426. &pOwnAddTbl);
  4427. pNmsDbOwnAddTbl = pOwnAddTbl;
  4428. NmsDbTotNoOfSlots = newNoOfSlots;
  4429. // Enlarge the (OwnerId<->VersNo) table if it is not at least as large as (OwnerId<->Addr) table.
  4430. if (RplPullMaxNoOfWins < NmsDbTotNoOfSlots)
  4431. {
  4432. RplPullAllocVersNoArray(&pRplPullOwnerVersNo, NmsDbTotNoOfSlots);
  4433. RplPullMaxNoOfWins = NmsDbTotNoOfSlots;
  4434. }
  4435. DBGPRINT2(
  4436. DET,
  4437. "ReadOwnAddTbl: Table sizes updated: (OwnerId<->Addr)[%d]; (OwnerId<->VersNo)[%d]\n",
  4438. NmsDbTotNoOfSlots,
  4439. RplPullMaxNoOfWins);
  4440. }
  4441. //
  4442. // If this is the first wins server's owner id then this has
  4443. // to be zero.
  4444. //
  4445. if (cOwners == 0)
  4446. {
  4447. ASSERT(OwnerId == 0);
  4448. if (OwnerId > 0)
  4449. {
  4450. DBGPRINT1(ERR, "Database error. The first owner in the owner-add table has owner id of (%d)\n", OwnerId);
  4451. WINSEVT_LOG_M(
  4452. WINS_FAILURE,
  4453. WINS_EVT_DB_INCONSISTENT
  4454. );
  4455. WINS_RAISE_EXC_M(WINS_EXC_DB_INCONSISTENT);
  4456. }
  4457. }
  4458. else
  4459. {
  4460. //
  4461. // Mark all entries in NmsDbOwnerAddTbl for which we did
  4462. // not find an owner id as deleted.
  4463. //
  4464. for (i = LastOwnerId + 1; i < OwnerId; i++)
  4465. {
  4466. (pNmsDbOwnAddTbl + i)->WinsState_e = NMSDB_E_WINS_DELETED;
  4467. }
  4468. }
  4469. // retrieve the address column
  4470. JetRetStat =
  4471. JetRetrieveColumn(
  4472. SesId,
  4473. TblId,
  4474. sOwnAddTblRow[OWN_ADD_ADDRESS_INDEX].Fid,
  4475. &((pNmsDbOwnAddTbl + OwnerId)->WinsAdd),
  4476. sizeof(COMM_ADD_T),
  4477. &ActFldLen,
  4478. 0,
  4479. NULL
  4480. );
  4481. DBGPRINT2(INIT, "ReadOwnAddTable: Owner Id (%d) - Address (%x)\n",
  4482. OwnerId, (pNmsDbOwnAddTbl + OwnerId)->WinsAdd.Add.IPAdd);
  4483. // retrieve the state column
  4484. CALL_M(
  4485. JetRetrieveColumn(
  4486. SesId,
  4487. TblId,
  4488. sOwnAddTblRow[OWN_ADD_STATE_INDEX].Fid,
  4489. &((pNmsDbOwnAddTbl + OwnerId)->WinsState_e),
  4490. sizeof(BYTE),
  4491. &ActFldLen,
  4492. 0,
  4493. NULL
  4494. )
  4495. );
  4496. // retrieve the version number column
  4497. CALL_M(
  4498. JetRetrieveColumn(
  4499. SesId,
  4500. TblId,
  4501. sOwnAddTblRow[OWN_ADD_VERSIONNO_INDEX].Fid,
  4502. &((pNmsDbOwnAddTbl + OwnerId)->StartVersNo),
  4503. sizeof(VERS_NO_T),
  4504. &ActFldLen,
  4505. 0,
  4506. NULL
  4507. )
  4508. );
  4509. // retrieve the Uid column
  4510. CALL_M(
  4511. JetRetrieveColumn(
  4512. SesId,
  4513. TblId,
  4514. sOwnAddTblRow[OWN_ADD_UID_INDEX].Fid,
  4515. &((pNmsDbOwnAddTbl + OwnerId)->Uid),
  4516. sizeof(WINS_UID_T),
  4517. &ActFldLen,
  4518. 0,
  4519. NULL
  4520. )
  4521. );
  4522. // pOwnAddTbl++; //increment ptr to point to next array element
  4523. LastOwnerId = OwnerId;
  4524. cOwners++;
  4525. } while(
  4526. JetMove(
  4527. SesId,
  4528. TblId,
  4529. JET_MoveNext,
  4530. 0 //grbit - use default (i.e. we want next record
  4531. ) >= 0
  4532. );
  4533. //
  4534. // Compare the count of owners found in the Owner-Address mapping
  4535. // table with the count we determined from the Name-Address mapping
  4536. // table (see GetMaxVersNos()). If the count is less
  4537. // the database is in an inconsistent state. This can
  4538. // mean any of the following:
  4539. //
  4540. // 1) WINS crashed in the middle of replication and recovery was not
  4541. // done properly prior to this invocation
  4542. //
  4543. // 2) The database got trashed due to some other external factors.
  4544. //
  4545. // This error condition is serious enough to warrant an exception.
  4546. // This should terminate WINS.
  4547. //
  4548. // The count can be more but not less. This is because when a
  4549. // WINS comes up, it registers itself in the Owner-Address mapping
  4550. // table. So it is possible that it might have gone down before
  4551. // registering anything. Also, it is possible for all records owned
  4552. // by a WINS server to be deleted.
  4553. //
  4554. if (cOwners < NmsDbNoOfOwners)
  4555. {
  4556. DBGPRINT2(ERR, "Database is inconsistent. The number of owners in the nam-add table (%d) is > in the own-add table (%d)\n",
  4557. NmsDbNoOfOwners,
  4558. cOwners);
  4559. WINSEVT_LOG_M(
  4560. WINS_FAILURE,
  4561. WINS_EVT_DB_INCONSISTENT
  4562. );
  4563. WINS_RAISE_EXC_M(WINS_EXC_DB_INCONSISTENT);
  4564. }
  4565. //
  4566. // Set the global equal to the number of owner records found in
  4567. // the owner-address table. If the global is < Cowners it means that
  4568. // the records owned by one or more WINS servers whose addresses were
  4569. // found in the owner - address mapping table have expired in our
  4570. // name - address mapping table.
  4571. //
  4572. #if 0
  4573. FUTURES("Do not include the WINS server that have a non-active state in the")
  4574. FUTURES("cOwners count")
  4575. NmsDbNoOfOwners = cOwners;
  4576. #endif
  4577. //
  4578. // Set the global to 1 more than the highest owner id found. This
  4579. // is done because we use this global to go over all entries in
  4580. // the NmsDbOwnAddTbl table (at several places - for example,
  4581. // RplFindOwnerId)
  4582. //
  4583. NmsDbNoOfOwners = OwnerId + 1;
  4584. //
  4585. // Do a sanity check. Make sure that there is no owner id with address
  4586. // same as ours. If there is such an owner id, mark the state as
  4587. // deleted.
  4588. //
  4589. // If the db at WINS A is used at WINS B and WINS A was and is a
  4590. // a partner of WINS B, we will have this situation. WINS B will
  4591. // see its records that got replicated to WINS A in the table at
  4592. // a non-zero (i.e. non-local partner) index. The 0th index is
  4593. // always claimed by the local WINS (WINS B in this example), so
  4594. // we can not have another index with the same address. Having it
  4595. // will cause clutter and also some unnecessary overhead at replication
  4596. // where a partner that gets the mappings can ask for version numbers
  4597. // that don't exist (if highest version number of records at the
  4598. // non-zero index is > that at 0 index). Admitted that eventually,
  4599. // the prior stated situation will no longer exist since the max.
  4600. // version number at index 0 will become > that at the non-zero index.
  4601. //
  4602. DBGPRINT0(DET, "ReadOwnAddTbl: Do a sanity check on the list of owners\n");
  4603. for (i = 1; i < NmsDbNoOfOwners; i++)
  4604. {
  4605. //
  4606. // If address is same as ours and state is ACTIVE, mark it
  4607. // deleted and get rid of all the database records.
  4608. //
  4609. if (
  4610. (WINSMSC_COMPARE_MEMORY_M(&(pNmsDbOwnAddTbl+i)->WinsAdd,
  4611. &NmsLocalAdd, sizeof(COMM_ADD_T))
  4612. == sizeof(COMM_ADD_T))
  4613. &&
  4614. ((pNmsDbOwnAddTbl+i)->WinsState_e == NMSDB_E_WINS_ACTIVE)
  4615. )
  4616. {
  4617. //
  4618. // Tell the sc. to wait since ObliterateWins can take
  4619. // a long time.
  4620. //
  4621. ENmsWinsUpdateStatus(MSECS_WAIT_WHEN_DEL_WINS);
  4622. RetStat = ObliterateWins(i, &(pNmsDbOwnAddTbl+i)->WinsAdd);
  4623. }
  4624. }
  4625. //
  4626. // Check for other duplicates
  4627. //
  4628. for (i = 1; i < NmsDbNoOfOwners; i++)
  4629. {
  4630. DWORD OwnerIdToDel;
  4631. for (n = i + 1; n < NmsDbNoOfOwners; n++)
  4632. {
  4633. if ((WINSMSC_COMPARE_MEMORY_M(&(pNmsDbOwnAddTbl+i)->WinsAdd,
  4634. &(pNmsDbOwnAddTbl+n)->WinsAdd, sizeof(COMM_ADD_T))
  4635. == sizeof(COMM_ADD_T))
  4636. &&
  4637. ((pNmsDbOwnAddTbl+i)->WinsState_e ==
  4638. (pNmsDbOwnAddTbl+n)->WinsState_e)
  4639. )
  4640. {
  4641. if ( (pNmsDbOwnAddTbl+i)->WinsState_e == NMSDB_E_WINS_ACTIVE)
  4642. {
  4643. if (!fLogged)
  4644. {
  4645. WINSEVT_LOG_M(WINS_FAILURE,
  4646. WINS_EVT_DUP_ENTRY_IN_DB);
  4647. fLogged = TRUE;
  4648. }
  4649. OwnerIdToDel =
  4650. LiLeq((pRplPullOwnerVersNo+i)->VersNo,
  4651. (pRplPullOwnerVersNo+n)->VersNo) ? i : n;
  4652. ENmsWinsUpdateStatus(MSECS_WAIT_WHEN_DEL_WINS);
  4653. RetStat = ObliterateWins(OwnerIdToDel,
  4654. &(pNmsDbOwnAddTbl+OwnerIdToDel)->WinsAdd);
  4655. }
  4656. }
  4657. }
  4658. }
  4659. DBGPRINT1(DET, "ReadOwnAddTbl. No of owners found = (%d)\n", NmsDbNoOfOwners);
  4660. return(RetStat);
  4661. }
  4662. STATUS
  4663. ObliterateWins(
  4664. DWORD OwnerToDel,
  4665. PCOMM_ADD_T pWinsAdd
  4666. )
  4667. /*++
  4668. Routine Description:
  4669. This function gets rid of all information pertaining to a WINS.
  4670. Arguments:
  4671. Externals Used:
  4672. None
  4673. Return Value:
  4674. Success status codes --
  4675. Error status codes --
  4676. Error Handling:
  4677. Called by:
  4678. Side Effects:
  4679. Comments:
  4680. This function assumes that it is being called at init time. So, when
  4681. calling NmsDbDelDataRecs, it does not request the same to enter a
  4682. critical section
  4683. --*/
  4684. {
  4685. VERS_NO_T MinVersNo;
  4686. VERS_NO_T MaxVersNo;
  4687. WINS_ASSIGN_INT_TO_LI_M(MinVersNo, 0);
  4688. DBGENTER("ObliterateWins\n");
  4689. //
  4690. // Set MaxVersNo to 0 also so that all records get
  4691. // deleted
  4692. //
  4693. MaxVersNo = MinVersNo;
  4694. WinsEvtLogDetEvt(TRUE, WINS_EVT_DUP_ENTRY_DEL, NULL, __LINE__, "ds", OwnerToDel, pWinsAdd->Add.IPAdd);
  4695. (pNmsDbOwnAddTbl+OwnerToDel)->WinsState_e = NMSDB_E_WINS_DELETED;
  4696. NmsDbWriteOwnAddTbl(
  4697. NMSDB_E_DELETE_REC,
  4698. OwnerToDel,
  4699. NULL,
  4700. NMSDB_E_WINS_DELETED,
  4701. NULL, NULL
  4702. );
  4703. //
  4704. // delete all the records in the database.
  4705. //
  4706. if (NmsDbDelDataRecs( OwnerToDel, MinVersNo, MaxVersNo, FALSE, FALSE) != WINS_SUCCESS) {
  4707. return(WINS_FAILURE);
  4708. }
  4709. WINS_ASSIGN_INT_TO_VERS_NO_M((pRplPullOwnerVersNo+OwnerToDel)->VersNo, 0);
  4710. WINS_ASSIGN_INT_TO_VERS_NO_M((pRplPullOwnerVersNo+OwnerToDel)->StartVersNo, 0);
  4711. //(pRplPullOwnerVersNo+OwnerToDel)->OldUid = 0;
  4712. WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_WINS_ENTRY_DELETED);
  4713. DBGLEAVE("ObliterateWins\n");
  4714. return(WINS_SUCCESS);
  4715. }
  4716. STATUS
  4717. NmsDbWriteOwnAddTbl (
  4718. IN NMSDB_TBL_ACTION_E TblAct_e,
  4719. IN DWORD OwnerId,
  4720. IN PCOMM_ADD_T pWinsAdd,
  4721. IN NMSDB_WINS_STATE_E WinsState_e,
  4722. IN PVERS_NO_T pStartVersNo,
  4723. IN PWINS_UID_T pUid
  4724. )
  4725. /*++
  4726. Routine Description:
  4727. This function is called to insert or modify a record in the
  4728. owner id to address mapping table
  4729. Arguments:
  4730. TblAct_e - the action to perform (Insert, delete, modify)
  4731. OwnerId - id of owner
  4732. pWinsAdd - Address of owner (can be NULL when action is to delete)
  4733. WinsState_e - State of record in the table
  4734. pStartVersNo - version number this WINS started from
  4735. Externals Used:
  4736. NmsDbNoOfOwners
  4737. Return Value:
  4738. Success status codes -- WINS_SUCCESS
  4739. Error status codes -- WINS_FAILURE
  4740. Error Handling:
  4741. Called by:
  4742. InitOwnAddTbl() in commapi.c, RplFindOwnerId
  4743. Side Effects:
  4744. Comments:
  4745. None
  4746. --*/
  4747. {
  4748. JET_ERR JetRetStat;
  4749. JET_TABLEID TblId;
  4750. JET_SESID SesId;
  4751. PWINSTHD_TLS_T pTls;
  4752. STATUS RetStat = WINS_SUCCESS;
  4753. GET_TLS_M(pTls);
  4754. ASSERT(pTls != NULL);
  4755. DBGPRINT2(FLOW, "ENTER: WriteOwnAddTbl. Action = (%d) for Owner id = (%d)\n", TblAct_e, OwnerId);
  4756. TblId = pTls->OwnAddTblId;
  4757. SesId = pTls->SesId;
  4758. switch(TblAct_e)
  4759. {
  4760. case(NMSDB_E_INSERT_REC):
  4761. CALL_M(JetBeginTransaction(SesId));
  4762. try {
  4763. CALL_M(JetPrepareUpdate(
  4764. SesId,
  4765. TblId,
  4766. JET_prepInsert
  4767. )
  4768. );
  4769. // add first column (ownerid field)
  4770. CALL_M( JetSetColumn(
  4771. SesId,
  4772. TblId,
  4773. sOwnAddTblRow[OWN_ADD_OWNERID_INDEX].Fid,
  4774. &OwnerId,
  4775. OWN_ADD_OWNERID_SIZE,
  4776. 0,
  4777. NULL /*optional info */
  4778. )
  4779. );
  4780. // add 2nd column (this is the address field)
  4781. CALL_M( JetSetColumn(
  4782. SesId,
  4783. TblId,
  4784. sOwnAddTblRow[OWN_ADD_ADDRESS_INDEX].Fid,
  4785. pWinsAdd,
  4786. sizeof(COMM_ADD_T),
  4787. 0,
  4788. NULL /*optional info */
  4789. )
  4790. );
  4791. // add the 3rd column (this is the state byte
  4792. CALL_M( JetSetColumn(
  4793. SesId,
  4794. TblId,
  4795. sOwnAddTblRow[OWN_ADD_STATE_INDEX].Fid,
  4796. &WinsState_e,
  4797. sizeof(BYTE),
  4798. 0,
  4799. NULL /*optional info */
  4800. )
  4801. );
  4802. // add the 4th column (this is the Vers. No
  4803. CALL_M( JetSetColumn(
  4804. SesId,
  4805. TblId,
  4806. sOwnAddTblRow[OWN_ADD_VERSIONNO_INDEX].Fid,
  4807. pStartVersNo,
  4808. sizeof(VERS_NO_T),
  4809. 0,
  4810. NULL /*optional info */
  4811. )
  4812. );
  4813. // add the 5th column (this is the Uid)
  4814. CALL_M( JetSetColumn(
  4815. SesId,
  4816. TblId,
  4817. sOwnAddTblRow[OWN_ADD_UID_INDEX].Fid,
  4818. pUid,
  4819. sizeof(WINS_UID_T),
  4820. 0,
  4821. NULL /*optional info */
  4822. )
  4823. );
  4824. CALL_M( JetUpdate (
  4825. SesId,
  4826. TblId,
  4827. NULL,
  4828. 0,
  4829. NULL
  4830. ));
  4831. }
  4832. finally {
  4833. if (AbnormalTermination())
  4834. {
  4835. DBGPRINT0(ERR,
  4836. "NmsDbWriteOwnAddTbl: Could not insert record in Owner to Address Mapping Tbl\n");
  4837. WINSEVT_LOG_M(
  4838. WINS_FAILURE,
  4839. WINS_EVT_CONFLICT_OWN_ADD_TBL
  4840. );
  4841. // if there is an abnormal termination, we already have an error
  4842. // code here. We shouldn't override it with any other error code.
  4843. JetRollback(SesId, JET_bitRollbackAll);
  4844. RetStat = WINS_FAILURE;
  4845. }
  4846. else
  4847. {
  4848. NmsDbNoOfOwners++;
  4849. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  4850. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  4851. CALL_M(JetCommitTransaction(SesId,
  4852. JET_bitCommitFlush));
  4853. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  4854. }
  4855. }
  4856. break;
  4857. //
  4858. // This case will be executed as a result of
  4859. // administrative actions or when the database (owner-address
  4860. // mapping table) shows that it was used earlier by a WINS
  4861. // at a different address (see ReadOwnAddTbl())
  4862. //
  4863. case(NMSDB_E_MODIFY_REC):
  4864. CALL_M( JetMakeKey(
  4865. SesId,
  4866. TblId,
  4867. &OwnerId,
  4868. OWN_ADD_OWNERID_SIZE,
  4869. JET_bitNewKey
  4870. )
  4871. );
  4872. if ( JetSeek(
  4873. SesId,
  4874. TblId,
  4875. JET_bitSeekEQ
  4876. ) == JET_errSuccess
  4877. )
  4878. {
  4879. CALL_M(JetBeginTransaction(SesId));
  4880. try {
  4881. JetRetStat = JetPrepareUpdate(
  4882. SesId,
  4883. TblId,
  4884. JET_prepReplace
  4885. );
  4886. if (
  4887. (JetRetStat != JET_errSuccess)
  4888. &&
  4889. (JetRetStat != JET_wrnNoWriteLock)
  4890. )
  4891. {
  4892. RET_M(JetRetStat);
  4893. }
  4894. // add 2nd column (this is the address field)
  4895. CALL_M( JetSetColumn(
  4896. SesId,
  4897. TblId,
  4898. sOwnAddTblRow[OWN_ADD_ADDRESS_INDEX].Fid,
  4899. pWinsAdd,
  4900. sizeof(COMM_ADD_T),
  4901. 0,
  4902. NULL /*optional info */
  4903. )
  4904. );
  4905. // add the 3rd column (this is the state byte
  4906. CALL_M( JetSetColumn(
  4907. SesId,
  4908. TblId,
  4909. sOwnAddTblRow[OWN_ADD_STATE_INDEX].Fid,
  4910. &WinsState_e,
  4911. sizeof(BYTE),
  4912. 0,
  4913. NULL /*optional info */
  4914. )
  4915. );
  4916. // add the 4th column (this is the Vers. No
  4917. CALL_M( JetSetColumn(
  4918. SesId,
  4919. TblId,
  4920. sOwnAddTblRow[OWN_ADD_VERSIONNO_INDEX].Fid,
  4921. pStartVersNo,
  4922. sizeof(VERS_NO_T),
  4923. 0,
  4924. NULL /*optional info */
  4925. )
  4926. );
  4927. // add the 5th column (this is the Uid)
  4928. CALL_M( JetSetColumn(
  4929. SesId,
  4930. TblId,
  4931. sOwnAddTblRow[OWN_ADD_UID_INDEX].Fid,
  4932. pUid,
  4933. sizeof(WINS_UID_T),
  4934. 0,
  4935. NULL /*optional info */
  4936. )
  4937. );
  4938. CALL_M( JetUpdate (
  4939. SesId,
  4940. TblId,
  4941. NULL,
  4942. 0,
  4943. NULL
  4944. ));
  4945. }
  4946. finally {
  4947. if (AbnormalTermination())
  4948. {
  4949. DBGPRINT0(ERR,
  4950. "NmsDbWriteOwnAddTbl: Could not modify record in Owner to Address Mapping Tbl\n");
  4951. WINSEVT_LOG_M(
  4952. WINS_FAILURE,
  4953. WINS_EVT_CONFLICT_OWN_ADD_TBL
  4954. );
  4955. // if there is an abnormal termination, we already have an error
  4956. // code here. We shouldn't override it with any other error code.
  4957. JetRollback(SesId, JET_bitRollbackAll);
  4958. RetStat = WINS_FAILURE;
  4959. }
  4960. else
  4961. {
  4962. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  4963. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  4964. CALL_M(JetCommitTransaction(SesId,
  4965. JET_bitCommitFlush));
  4966. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  4967. }
  4968. }
  4969. }
  4970. else //did not find record
  4971. {
  4972. DBGPRINT0(EXC, "NmsDbOwnAddTbl: Weird: Could not seek to a record is to be modified\n");
  4973. WINSEVT_LOG_M(
  4974. WINS_FAILURE,
  4975. WINS_EVT_SFT_ERR
  4976. );
  4977. WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
  4978. }
  4979. break;
  4980. case(NMSDB_E_DELETE_REC):
  4981. CALL_M( JetMakeKey(
  4982. SesId,
  4983. TblId,
  4984. &OwnerId,
  4985. OWN_ADD_OWNERID_SIZE,
  4986. JET_bitNewKey
  4987. )
  4988. );
  4989. if ( JetSeek(
  4990. SesId,
  4991. TblId,
  4992. JET_bitSeekEQ
  4993. ) == JET_errSuccess
  4994. )
  4995. {
  4996. try {
  4997. CALL_M(JetBeginTransaction(SesId));
  4998. CALL_M(JetDelete(SesId, TblId));
  4999. DBGPRINT1(SCV, "WriteOwnAddTbl: Deleted owner id = (%d) from table\n", OwnerId);
  5000. }
  5001. finally {
  5002. if (AbnormalTermination())
  5003. {
  5004. DBGPRINT0(ERR,
  5005. "NmsDbWriteOwnAddTbl: Could not delete record in Owner to Address Mapping Tbl\n");
  5006. WINSEVT_LOG_M(
  5007. WINS_FAILURE,
  5008. WINS_EVT_CONFLICT_OWN_ADD_TBL
  5009. );
  5010. // if there is an abnormal termination, we already have an error
  5011. // code here. We shouldn't override it with any other error code.
  5012. JetRollback(SesId, JET_bitRollbackAll);
  5013. RetStat = WINS_FAILURE;
  5014. }
  5015. else
  5016. {
  5017. //
  5018. // NOTE: Do not decrement
  5019. // NmsDbNoOfOwners since that indicates
  5020. // the number of WINS owners in the
  5021. // in-memory table (in all states)
  5022. //
  5023. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  5024. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  5025. CALL_M(JetCommitTransaction(SesId,
  5026. JET_bitCommitFlush));
  5027. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  5028. }
  5029. } // end of finally
  5030. }
  5031. else //did not find record
  5032. {
  5033. DBGPRINT0(EXC, "NmsDbOwnAddTbl: Weird: Could not seek to a record to be deleted \n");
  5034. WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
  5035. }
  5036. break;
  5037. default:
  5038. DBGPRINT1(ERR, "Invalid Action Code - (%d)\n", TblAct_e);
  5039. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
  5040. RetStat = WINS_FAILURE;
  5041. break;
  5042. }
  5043. DBGLEAVE("WriteOwnAddTbl\n");
  5044. return(RetStat);
  5045. }
  5046. VOID
  5047. NmsDbThdInit(
  5048. WINS_CLIENT_E Client_e
  5049. )
  5050. /*++
  5051. Routine Description:
  5052. This function is called by each thread that wishes to init with
  5053. the database.
  5054. Arguments:
  5055. Client_e - indicates which thread it is
  5056. Externals Used:
  5057. None
  5058. Return Value:
  5059. Success status codes -- WINS_SUCCESS
  5060. Error status codes -- WINS_FAILURE
  5061. Error Handling:
  5062. Called by:
  5063. The init functions of the various threads
  5064. Side Effects:
  5065. Comments:
  5066. This function is not to be called by the manin thread of the process
  5067. That thread calls the NmsDbInit function.
  5068. --*/
  5069. {
  5070. PWINSTHD_TLS_T pTls = NULL;
  5071. DWORD Error = 0;
  5072. BOOL fRetVal = TRUE;
  5073. WinsMscAlloc(sizeof(WINSTHD_TLS_T), &pTls);
  5074. #ifdef WINSDBG
  5075. pTls->Client_e = Client_e;
  5076. #endif
  5077. //
  5078. // Start a session.
  5079. //
  5080. FUTURES("When security story regarding JET is complete, we might want to")
  5081. FUTURES("change the following. Until then, this should do")
  5082. CALL_N_RAISE_EXC_IF_ERR_M( JetBeginSession(
  5083. sJetInstance,
  5084. &pTls->SesId,
  5085. NAMUSR,
  5086. PASSWD
  5087. )
  5088. );
  5089. //
  5090. // Open the database
  5091. //
  5092. CALL_N_RAISE_EXC_IF_ERR_M( JetOpenDatabase(
  5093. pTls->SesId,
  5094. //NmsDbDatabaseFileName,
  5095. WinsCnf.pWinsDb,
  5096. NULL, /*the default engine*/
  5097. &pTls->DbId,
  5098. 0 //shared access
  5099. )
  5100. );
  5101. /*
  5102. * Let us set the TLS storage
  5103. */
  5104. fRetVal = TlsSetValue(WinsTlsIndex, pTls);
  5105. if (!fRetVal)
  5106. {
  5107. Error = GetLastError();
  5108. WINSEVT_LOG_M(Error, WINS_EVT_CANT_INIT_W_DB);
  5109. WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
  5110. }
  5111. else
  5112. {
  5113. //
  5114. // RPC threads come and go. Since the count NmsTotalTermThdCnt
  5115. // represents the number of threads that need to be terminated
  5116. // at process termination time we include only those threads
  5117. // that we are guaranteed to have in the process (with active
  5118. // db sessions).
  5119. //
  5120. // Also, the main thread is always accounted for in the
  5121. // NmsTotalTrmThdCnt counter.
  5122. //
  5123. if ((Client_e != WINS_E_WINSRPC) && (Client_e != WINS_E_NMS))
  5124. {
  5125. //
  5126. // Increment the count of threads that have initialized
  5127. // with the db engine. This count will be used by the
  5128. // main thread to determine the number of threads that
  5129. // must wait for prior to terminating the process.
  5130. //
  5131. EnterCriticalSection(&NmsTermCrtSec);
  5132. NmsTotalTrmThdCnt++;
  5133. LeaveCriticalSection(&NmsTermCrtSec);
  5134. }
  5135. }
  5136. return;
  5137. }
  5138. JET_ERR
  5139. UpdateDb (
  5140. JET_SESID SesId,
  5141. JET_TABLEID TblId,
  5142. PNMSDB_ROW_INFO_T pRowInfo,
  5143. ULONG TypOfUpd
  5144. )
  5145. /*++
  5146. Routine Description:
  5147. This function is called to insert a record in the name - address
  5148. mapping table of the database
  5149. Arguments:
  5150. SesId - Session Id
  5151. TblId - Table Id
  5152. pRowInfo - Row to insert
  5153. TypOfUp - Type of Update (insertion or replacement)
  5154. Externals Used:
  5155. None
  5156. Return Value:
  5157. Success status codes -- JET_ErrSuccess
  5158. Error status codes -- Jet error status codes
  5159. Error Handling:
  5160. Called by:
  5161. NmsDbInsertRowInd,
  5162. NmsDbUpdateRow
  5163. Side Effects:
  5164. Comments:
  5165. None
  5166. --*/
  5167. {
  5168. DWORD EntryFlag = 0;
  5169. JET_ERR JetRetStat;
  5170. //JET_SETINFO SetInfo;
  5171. #ifdef WINSDBG
  5172. BOOL fUpd = FALSE;
  5173. #endif
  5174. CALL_M(JetBeginTransaction(SesId));
  5175. try {
  5176. JetRetStat = JetPrepareUpdate(
  5177. SesId,
  5178. TblId,
  5179. TypOfUpd
  5180. );
  5181. //
  5182. // Starting from rel118.0, JetPrepareUpdate can return
  5183. // JET_wrnNoWriteLock when called to replace a record at
  5184. // transaction level 0. We should just ignore it
  5185. //
  5186. if (JetRetStat != JET_errSuccess)
  5187. {
  5188. if (
  5189. !((JetRetStat == JET_wrnNoWriteLock)
  5190. &&
  5191. (TypOfUpd == JET_prepReplace))
  5192. )
  5193. {
  5194. RET_M(JetRetStat);
  5195. }
  5196. }
  5197. // add first column (clustered index)
  5198. if (TypOfUpd != JET_prepReplace)
  5199. {
  5200. JETRET_M( JetSetColumn(
  5201. SesId,
  5202. TblId,
  5203. sNamAddTblRow[NAM_ADD_NAME_INDEX].Fid,
  5204. pRowInfo->pName,
  5205. pRowInfo->NameLen,
  5206. 0,
  5207. NULL /*optional info */
  5208. )
  5209. );
  5210. }
  5211. PERF("Make check for unique record first. Also, remove the shifting")
  5212. PERF("NodeType field for spec. grp. When we start doing this")
  5213. PERF("do not set NodeType to 0 in NmsNmhReplGrpMem in nmsnmh.c")
  5214. if (
  5215. NMSDB_ENTRY_SPEC_GRP_M(pRowInfo->EntTyp)
  5216. ||
  5217. NMSDB_ENTRY_MULTIHOMED_M(pRowInfo->EntTyp)
  5218. )
  5219. {
  5220. EntryFlag = pRowInfo->EntTyp
  5221. |
  5222. (pRowInfo->NodeTyp << NMSDB_SHIFT_NODE_TYP)
  5223. |
  5224. (pRowInfo->fStatic << NMSDB_SHIFT_STATIC)
  5225. |
  5226. (pRowInfo->fLocal ? NMSDB_BIT_LOCAL : 0)
  5227. |
  5228. (pRowInfo->EntryState_e << NMSDB_SHIFT_STATE);
  5229. JETRET_M( InsertGrpMemsInCol(
  5230. SesId,
  5231. TblId,
  5232. pRowInfo,
  5233. TypOfUpd
  5234. )
  5235. );
  5236. }
  5237. else // it is a unique entry or a normal group entry
  5238. {
  5239. if (NMSDB_ENTRY_NORM_GRP_M(pRowInfo->EntTyp))
  5240. {
  5241. EntryFlag = pRowInfo->EntTyp
  5242. |
  5243. (pRowInfo->fStatic << NMSDB_SHIFT_STATIC)
  5244. |
  5245. (pRowInfo->EntryState_e << NMSDB_SHIFT_STATE);
  5246. }
  5247. else // it is a Unique entry
  5248. {
  5249. EntryFlag =
  5250. pRowInfo->EntTyp
  5251. |
  5252. (pRowInfo->NodeTyp << NMSDB_SHIFT_NODE_TYP)
  5253. |
  5254. (pRowInfo->fLocal ? NMSDB_BIT_LOCAL : 0)
  5255. |
  5256. (pRowInfo->fStatic << NMSDB_SHIFT_STATIC)
  5257. |
  5258. (pRowInfo->EntryState_e << NMSDB_SHIFT_STATE);
  5259. }
  5260. FUTURES("If in the future, we support more than one address for a unique name")
  5261. FUTURES("we will check pRowInfo for the number of addresses (another field)")
  5262. FUTURES("and then specify the right size to JetSetColumn below")
  5263. //
  5264. // add second column (IP address)
  5265. //
  5266. // Note: Even though for Normal groups there is no need to
  5267. // set the address, we do it anyway. This is to save
  5268. // an if test which wlll slow down the registrations (inside
  5269. // a critical section) of unique entries (form the bulk
  5270. // of registration traffic).
  5271. //
  5272. FUTURES("Don't distinguish between unique and group entries. Store Time stamp")
  5273. FUTURES("and owner id along with address in case of unique entry. This will")
  5274. FUTURES("help get rid of some code from this function")
  5275. // JetRetStat = JetSetColumn(
  5276. JETRET_M( JetSetColumn(
  5277. SesId,
  5278. TblId,
  5279. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  5280. pRowInfo->pNodeAdd,
  5281. sizeof(COMM_ADD_T),
  5282. //Grbit,
  5283. 0,
  5284. //pSetInfo
  5285. NULL /*optional info */
  5286. )
  5287. );
  5288. }
  5289. // add third column (this is the flag byte */
  5290. JETRET_M( JetSetColumn(
  5291. SesId,
  5292. TblId,
  5293. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  5294. &EntryFlag,
  5295. sizeof(EntryFlag),
  5296. 0,
  5297. NULL /*optional info */
  5298. )
  5299. );
  5300. //
  5301. // If the version number is not to be incremented, there is no
  5302. // need to increment the owner id. It must remain the same.
  5303. //
  5304. if (pRowInfo->fUpdVersNo)
  5305. {
  5306. // add 4th column (this is the owner byte */
  5307. JETRET_M( JetSetColumn(
  5308. SesId,
  5309. TblId,
  5310. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  5311. &pRowInfo->OwnerId,
  5312. NAM_ADD_OWNERID_SIZE,
  5313. 0,
  5314. NULL /*optional info */
  5315. )
  5316. );
  5317. // add 5th column (this is the version number long(DWORD)
  5318. JETRET_M( JetSetColumn(
  5319. SesId,
  5320. TblId,
  5321. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  5322. &(pRowInfo->VersNo),
  5323. sizeof(VERS_NO_T),
  5324. 0,
  5325. NULL /*optional info */
  5326. )
  5327. );
  5328. #ifdef WINSDBG
  5329. fUpd = TRUE;
  5330. #endif
  5331. }
  5332. //
  5333. // When the conflict is between two internet group entries,
  5334. // (replica -- Tombstone, database entry -- Active), we do
  5335. // not update the timestamp (Check out -- ClashAtReplGrpMems
  5336. // in nmsnmh.c to get a better insight into this).
  5337. //
  5338. if (pRowInfo->fUpdTimeStamp)
  5339. {
  5340. // add 6th column (this is the time stamp) */
  5341. JETRET_M( JetSetColumn(
  5342. SesId,
  5343. TblId,
  5344. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  5345. &(pRowInfo->TimeStamp),
  5346. sizeof(DWORD),
  5347. 0,
  5348. NULL /*optional info */
  5349. )
  5350. );
  5351. }
  5352. JetRetStat = JetUpdate (
  5353. SesId,
  5354. TblId,
  5355. NULL,
  5356. 0L,
  5357. NULL
  5358. );
  5359. } // end of try block
  5360. finally {
  5361. if (AbnormalTermination() || JetRetStat != JET_errSuccess)
  5362. {
  5363. // if there is an abnormal termination, we already have an error
  5364. // code here. We shouldn't override it with any other error code.
  5365. JetRollback(SesId, JET_bitRollbackAll);
  5366. }
  5367. else
  5368. {
  5369. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  5370. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  5371. CALL_M(JetCommitTransaction(SesId, /*CommitGrBit |*/ JET_bitCommitFlush));
  5372. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  5373. }
  5374. }
  5375. #ifdef WINSDBG
  5376. if (JetRetStat == JET_errSuccess)
  5377. {
  5378. NMSNMH_UPD_UPD_CTRS_M(fUpd, TypOfUpd != JET_prepReplace ? FALSE : TRUE, pRowInfo);
  5379. }
  5380. #endif
  5381. return(JetRetStat);
  5382. }
  5383. STATUS
  5384. NmsDbUpdateVersNo (
  5385. BOOL fAfterClash,
  5386. PNMSDB_ROW_INFO_T pRowInfo,
  5387. PNMSDB_STAT_INFO_T pStatusInfo
  5388. )
  5389. /*++
  5390. Routine Description:
  5391. This function is called to update a record in the name - address
  5392. mapping table of the database.
  5393. Arguments:
  5394. fAfterClash - indicates whether the update is being done after
  5395. a conflict resolution.
  5396. Externals Used:
  5397. None
  5398. Return Value:
  5399. Success status codes --
  5400. Error status codes --
  5401. Error Handling:
  5402. Called by:
  5403. NmsNmhReplRegInd,
  5404. Side Effects:
  5405. Comments:
  5406. None
  5407. --*/
  5408. {
  5409. JET_TABLEID TblId;
  5410. JET_SESID SesId;
  5411. PWINSTHD_TLS_T pTls;
  5412. STATUS RetStat = WINS_SUCCESS;
  5413. JET_ERR JetRetStat;
  5414. DWORD ActFldLen;
  5415. DBGENTER("NmsDbUpdVersNo\n");
  5416. pTls = TlsGetValue(WinsTlsIndex);
  5417. // No need to check whether pTls is NON-NULL. It has to be
  5418. TblId = pTls->NamAddTblId;
  5419. SesId = pTls->SesId;
  5420. pStatusInfo->StatCode = NMSDB_SUCCESS;
  5421. CALL_M( JetMakeKey(
  5422. SesId,
  5423. TblId,
  5424. pRowInfo->pName,
  5425. pRowInfo->NameLen,
  5426. JET_bitNewKey
  5427. )
  5428. );
  5429. if ( (JetRetStat = JetSeek(
  5430. SesId,
  5431. TblId,
  5432. JET_bitSeekEQ
  5433. )
  5434. ) == JET_errRecordNotFound
  5435. )
  5436. {
  5437. if (fAfterClash)
  5438. {
  5439. /*
  5440. There is some serious error.
  5441. This condition should never occur because this thread
  5442. got a conflict on a record earlier while inside the
  5443. NmsNmhNamRegCrtSec. Since the thread never got out of the
  5444. critical section prior to calling this function, there is
  5445. no reason why we should now not be able to find the record
  5446. */
  5447. DBGPRINT1(ERR,
  5448. "NmsDbUpdateVersNo: Could not find record (%s) -- WEIRD\n", pRowInfo->pName);
  5449. WINSEVT_LOG_M(JetRetStat, WINS_EVT_F_CANT_FIND_REC);
  5450. ASSERTMSG(0, "SEEK ERROR");
  5451. return(WINS_FAILURE);
  5452. }
  5453. else
  5454. {
  5455. DBGPRINT1(DET,
  5456. "NmsDbUpdateVersNo: Could not find record (%s). It might have been deleted\n", pRowInfo->pName);
  5457. WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_CANT_FIND_REC);
  5458. return(WINS_SUCCESS);
  5459. }
  5460. }
  5461. else
  5462. {
  5463. if (JetRetStat != JET_errSuccess)
  5464. {
  5465. DBGPRINT1(ERR,
  5466. "NmsDbRelRow: Seek returned Error (%d)\n",
  5467. JetRetStat);
  5468. WINSEVT_LOG_M(JetRetStat, WINS_EVT_DATABASE_ERR);
  5469. return(WINS_FAILURE);
  5470. }
  5471. }
  5472. CALL_M(JetBeginTransaction(SesId));
  5473. try {
  5474. JetRetStat = JetPrepareUpdate(
  5475. SesId,
  5476. TblId,
  5477. JET_prepReplace
  5478. );
  5479. if ((JetRetStat != JET_errSuccess) && (JetRetStat != JET_wrnNoWriteLock))
  5480. {
  5481. CALL_M(JetRetStat);
  5482. }
  5483. FUTURES("Remove adding of name")
  5484. #if 0
  5485. // add first column (clusterred index)
  5486. CALL_M( JetSetColumn(
  5487. SesId,
  5488. TblId,
  5489. sNamAddTblRow[NAM_ADD_NAME_INDEX].Fid,
  5490. pRowInfo->pName,
  5491. pRowInfo->NameLen,
  5492. 0,
  5493. NULL /*optional info */
  5494. )
  5495. );
  5496. #endif
  5497. //
  5498. // retrieve the owner id field for doing sanity check
  5499. //
  5500. #if !NEW_OWID
  5501. pStatusInfo->OwnerId = 0;
  5502. #endif
  5503. CALL_M(
  5504. JetRetrieveColumn(
  5505. SesId,
  5506. TblId,
  5507. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  5508. &pStatusInfo->OwnerId,
  5509. NAM_ADD_OWNERID_SIZE,
  5510. &ActFldLen,
  5511. 0,
  5512. NULL
  5513. )
  5514. );
  5515. //
  5516. // If this WINS does not own the record, raise an exception
  5517. //
  5518. // This should never happen since we never left the critical
  5519. // section after the clash.
  5520. //
  5521. if(pStatusInfo->OwnerId != NMSDB_LOCAL_OWNER_ID)
  5522. {
  5523. if (fAfterClash)
  5524. {
  5525. pStatusInfo->StatCode = NMSDB_NO_SUCH_ROW;
  5526. WINSEVT_LOG_M(pStatusInfo->OwnerId, WINS_EVT_RECORD_NOT_OWNED);
  5527. DBGPRINT1(EXC,
  5528. "NmsDbUpdVersNo: Record with name (%s) not owned by this WINS\n",
  5529. pRowInfo->pName);
  5530. WINS_RAISE_EXC_M(WINS_EXC_RECORD_NOT_OWNED);
  5531. }
  5532. else
  5533. {
  5534. DBGPRINT1(DET,
  5535. "NmsDbUpdateVersNo: The record with name (%s) is no longer owned by this WINS", pRowInfo->pName);
  5536. WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_RECORD_NOT_OWNED);
  5537. return(WINS_SUCCESS);
  5538. }
  5539. }
  5540. // add 5th column (this is the version number long(DWORD) */
  5541. CALL_M( JetSetColumn(
  5542. SesId,
  5543. TblId,
  5544. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  5545. &(pRowInfo->VersNo),
  5546. sizeof(VERS_NO_T),
  5547. 0,
  5548. NULL /*optional info */
  5549. )
  5550. );
  5551. //
  5552. // determine if the time stamp needs to be updated
  5553. //
  5554. if (pRowInfo->fUpdTimeStamp)
  5555. {
  5556. // add 6th column (this is the time stamp) */
  5557. CALL_M( JetSetColumn(
  5558. SesId,
  5559. TblId,
  5560. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  5561. &(pRowInfo->TimeStamp),
  5562. sizeof(DWORD),
  5563. 0,
  5564. NULL /*optional info */
  5565. )
  5566. );
  5567. }
  5568. CALL_M( JetUpdate (
  5569. SesId,
  5570. TblId,
  5571. NULL,
  5572. 0L,
  5573. NULL
  5574. )
  5575. );
  5576. } // end of try ..
  5577. finally {
  5578. if (AbnormalTermination())
  5579. {
  5580. // if there is an abnormal termination, we already have an error
  5581. // code here. We shouldn't override it with any other error code.
  5582. JetRollback(SesId, JET_bitRollbackAll);
  5583. }
  5584. else
  5585. {
  5586. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  5587. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  5588. CALL_M(JetCommitTransaction(SesId, JET_bitCommitFlush));
  5589. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  5590. }
  5591. }
  5592. DBGLEAVE("NmsDbUpdVersNo\n");
  5593. return(RetStat);
  5594. }
  5595. STATUS
  5596. NmsDbEndSession (
  5597. VOID
  5598. )
  5599. /*++
  5600. Routine Description:
  5601. This function closes the table, the database and ends the session
  5602. Arguments:
  5603. None
  5604. Externals Used:
  5605. WinsTlsIndex
  5606. Return Value:
  5607. Success status codes -- WINS_SUCCESS
  5608. Error status codes -- WINS_FAILURE
  5609. Error Handling:
  5610. Errors are logged
  5611. Called by:
  5612. WaitUntilSignaled in nms.c (by an nbt thread when it is signaled by
  5613. the main thread for termination purposes)
  5614. Side Effects:
  5615. Comments:
  5616. None
  5617. --*/
  5618. {
  5619. PWINSTHD_TLS_T pTls;
  5620. STATUS RetStat = WINS_SUCCESS;
  5621. pTls = TlsGetValue(WinsTlsIndex);
  5622. if (pTls == NULL)
  5623. {
  5624. RetStat = WINS_FAILURE;
  5625. }
  5626. else
  5627. {
  5628. if (pTls->fNamAddTblOpen)
  5629. {
  5630. CALL_M(JetCloseTable(
  5631. pTls->SesId,
  5632. pTls->NamAddTblId
  5633. )
  5634. );
  5635. }
  5636. if (pTls->fOwnAddTblOpen)
  5637. {
  5638. CALL_M(JetCloseTable(
  5639. pTls->SesId,
  5640. pTls->OwnAddTblId
  5641. )
  5642. );
  5643. }
  5644. CALL_M(JetCloseDatabase(
  5645. pTls->SesId,
  5646. pTls->DbId,
  5647. 0 //find out what grbit can be used for
  5648. )
  5649. );
  5650. CALL_M(JetEndSession(
  5651. pTls->SesId,
  5652. 0 //find out what grbit can be used for
  5653. )
  5654. );
  5655. }
  5656. //
  5657. // deallocate the TLS storage
  5658. //
  5659. WinsMscDealloc(pTls);
  5660. return(RetStat);
  5661. }
  5662. STATUS
  5663. GetGrpMem (
  5664. IN JET_SESID SesId,
  5665. IN JET_TABLEID TblId,
  5666. IN PNMSDB_ROW_INFO_T pRowInfo,
  5667. IN DWORD_PTR CurrentTime,
  5668. // IN OUT PNMSDB_NODE_ADDS_T pNodeAdds,
  5669. IN OUT PNMSDB_STAT_INFO_T pStatInfo,
  5670. IN BOOL fStatic,
  5671. OUT LPBOOL pfIsMem
  5672. )
  5673. /*++
  5674. Routine Description:
  5675. This function is called to get all the active members of a
  5676. special group
  5677. Arguments:
  5678. SesId - Id of the session started with the db
  5679. TblId - Id of the name -address mapping table
  5680. pRowInfo - Used to pass current time and address of the client
  5681. (when the client sends the release request)
  5682. pNodeAdds - group memnbers that are still active
  5683. fStatic - indicates whether the record is STATIC or not.
  5684. pfIsMem - indicates whether the client is a member of the group
  5685. Externals Used:
  5686. None
  5687. Return Value:
  5688. Success status codes -- WINS_SUCCESS
  5689. Error status codes -- WINS_FAILURE
  5690. Error Handling:
  5691. Called by:
  5692. NmsDbRelRow, NmsDbInsertRowGrp
  5693. Side Effects:
  5694. Comments:
  5695. None
  5696. --*/
  5697. {
  5698. DWORD i;
  5699. DWORD No = 0; //needs to be inited here
  5700. JET_RETINFO RetInfo;
  5701. DWORD ActFldLen = 0;
  5702. DWORD TimeToExpire;
  5703. NMSDB_GRP_MEM_ENTRY_T GrpMem;
  5704. JET_ERR JetRetStat;
  5705. *pfIsMem = FALSE; //Assume that the client is not a member
  5706. //of the group
  5707. /* retrieve the number of addresses info*/
  5708. RetInfo.itagSequence = 1;
  5709. RetInfo.cbStruct = sizeof(JET_RETINFO);
  5710. RetInfo.ibLongValue = 0;
  5711. JetRetStat = JetRetrieveColumn(
  5712. SesId,
  5713. TblId,
  5714. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  5715. &pStatInfo->NodeAdds.NoOfMems,
  5716. sizeof(pStatInfo->NodeAdds.NoOfMems),
  5717. &ActFldLen,
  5718. 0,
  5719. &RetInfo
  5720. );
  5721. if (
  5722. (JetRetStat != JET_errSuccess)
  5723. &&
  5724. (JetRetStat != JET_wrnBufferTruncated)
  5725. )
  5726. {
  5727. CALL_M(JetRetStat);
  5728. }
  5729. ASSERT(pStatInfo->NodeAdds.NoOfMems <= NMSDB_MAX_MEMS_IN_GRP);
  5730. DBGPRINT1(FLOW, "GetGrpMems: No Of members in group (expired and non-expired) are (%d)\n", pStatInfo->NodeAdds.NoOfMems);
  5731. NOTE("Remove this check once JET is error free")
  5732. if (pStatInfo->NodeAdds.NoOfMems > NMSDB_MAX_MEMS_IN_GRP)
  5733. {
  5734. WINSEVT_STRS_T EvtStrs;
  5735. WCHAR String[NMSDB_MAX_NAM_LEN];
  5736. EvtStrs.NoOfStrs = 1;
  5737. (VOID)WinsMscConvertAsciiStringToUnicode(
  5738. pRowInfo->pName,
  5739. (LPBYTE)String,
  5740. NMSDB_MAX_NAM_LEN);
  5741. EvtStrs.pStr[0] = String;
  5742. pStatInfo->NodeAdds.NoOfMems = 0;
  5743. WINSEVT_LOG_STR_M(WINS_EVT_DATABASE_CORRUPTION, &EvtStrs);
  5744. }
  5745. RetInfo.ibLongValue = sizeof(pStatInfo->NodeAdds.NoOfMems);
  5746. for (i=0; i < pStatInfo->NodeAdds.NoOfMems; i++)
  5747. {
  5748. JetRetStat = JetRetrieveColumn(
  5749. SesId,
  5750. TblId,
  5751. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  5752. &GrpMem,
  5753. sizeof(GrpMem),
  5754. &ActFldLen,
  5755. 0,
  5756. &RetInfo
  5757. );
  5758. if (
  5759. (JetRetStat != JET_errSuccess)
  5760. &&
  5761. (JetRetStat != JET_wrnBufferTruncated)
  5762. )
  5763. {
  5764. CALL_M(JetRetStat);
  5765. }
  5766. //
  5767. // If the grp has expired, set TimeToExpire to 0
  5768. //
  5769. if (CurrentTime >= GrpMem.TimeStamp)
  5770. {
  5771. TimeToExpire = 0;
  5772. }
  5773. else
  5774. {
  5775. TimeToExpire = 1;
  5776. }
  5777. //
  5778. // If this is a STATIC record but not a user defined spec. grp or
  5779. // if the member was registered by another WINS or if
  5780. // the member is still active, keep it (i.e. return it
  5781. // in the NodeAdds array.) We drop all non-owned members which
  5782. // have expired.
  5783. //
  5784. // Note 1C groups are special even if user defines them in the
  5785. // lmhosts file
  5786. //
  5787. if (
  5788. (fStatic && (!(NMSDB_ENTRY_USER_SPEC_GRP_M(pRowInfo->pName, pStatInfo->EntTyp))))
  5789. ||
  5790. (GrpMem.OwnerId != NMSDB_LOCAL_OWNER_ID)
  5791. ||
  5792. TimeToExpire
  5793. )
  5794. {
  5795. pStatInfo->NodeAdds.Mem[No++] = GrpMem;
  5796. if (pRowInfo->NodeAdds.Mem[0].Add.Add.IPAdd
  5797. == GrpMem.Add.Add.IPAdd)
  5798. {
  5799. *pfIsMem = TRUE;
  5800. }
  5801. }
  5802. if (No == NMSDB_MAX_MEMS_IN_GRP)
  5803. {
  5804. /*
  5805. * Group limit reached
  5806. */
  5807. break;
  5808. }
  5809. RetInfo.ibLongValue += sizeof(GrpMem);
  5810. } //end of for
  5811. pStatInfo->NodeAdds.NoOfMems = No;
  5812. DBGPRINT1(FLOW, "GetGrpMems: No Of non-expired members in group are (%d)\n", pStatInfo->NodeAdds.NoOfMems);
  5813. #ifdef WINSDBG
  5814. if (pStatInfo->NodeAdds.NoOfMems > NMSDB_MAX_MEMS_IN_GRP)
  5815. {
  5816. DBGPRINT4(SPEC, "GetGrpMems: No Of non-expired members in group %s are (%d). Vers. No to insert is (%d %d)\n", pRowInfo->pName, pStatInfo->NodeAdds.NoOfMems, pRowInfo->VersNo.HighPart, pRowInfo->VersNo.LowPart);
  5817. }
  5818. #endif
  5819. return(WINS_SUCCESS);
  5820. }
  5821. VOID
  5822. NmsDbRelRes(
  5823. VOID
  5824. )
  5825. /*++
  5826. Routine Description:
  5827. This function releases all the resources held by the Database Engine
  5828. (JET)
  5829. Arguments:
  5830. None
  5831. Externals Used:
  5832. None
  5833. Return Value:
  5834. None
  5835. Error Handling:
  5836. Called by:
  5837. WinsMain
  5838. Side Effects:
  5839. Comments:
  5840. This function must be called by the thread that did the attach.
  5841. So, it has to be the main thread.
  5842. --*/
  5843. {
  5844. // PWINSTHD_TLS_T pTls;
  5845. JET_ERR JetRetStat = JET_errSuccess;
  5846. // JET_SESID SesId;
  5847. // BOOL fOutOfReck;
  5848. DBGENTER("NmsDbRelRes\n");
  5849. //
  5850. // Call JetTerm only if there is no abrupt termination. Currently,
  5851. // JetTerm will hang if it is called without all sessions being
  5852. // terminated. Terminating abruptly without calling JetTerm
  5853. // is sort of equivalent to power failure kind of situation.
  5854. // Recovery will happen under the covers the next time WINS server
  5855. // is invoked -- Ian Jose 10/18/93.
  5856. //
  5857. if (!fNmsAbruptTerm /*&& !fOutOfReck*/)
  5858. {
  5859. DBGPRINT0(DET, "NmsDbRelRes: JetTerm being called\n");
  5860. #if DYNLOADJET
  5861. if (DynLoadJetVersion >= DYN_LOAD_JET_500)
  5862. {
  5863. (VOID)JetTerm2(sJetInstance, JET_bitTermComplete);//no need to check to the return value
  5864. }
  5865. else
  5866. #endif
  5867. {
  5868. (VOID)JetTerm(sJetInstance);//no need to check to the return value
  5869. }
  5870. }
  5871. DBGLEAVE("NmsDbRelRes\n");
  5872. return;
  5873. }
  5874. STATUS
  5875. GetMaxVersNos(
  5876. JET_SESID SesId,
  5877. JET_TABLEID TblId
  5878. )
  5879. /*++
  5880. Routine Description:
  5881. This function is called at initialization time to get the
  5882. max version number for records owned by different WINS servers
  5883. in the database.
  5884. Arguments:
  5885. SesId - Jet Session id
  5886. TblId - Table Id of the Name-Address Mapping table
  5887. Externals Used:
  5888. None
  5889. Return Value:
  5890. Success status codes --
  5891. Error status codes --
  5892. Error Handling:
  5893. Called by:
  5894. NmsDbInit
  5895. Side Effects:
  5896. Comments:
  5897. This function is called at initialization time. If in the future,
  5898. it gets called during stable state, we need to have a critical section
  5899. around the update of NmsDbNoOfOwners var.
  5900. --*/
  5901. {
  5902. #if NEW_OWID
  5903. DWORD OwnerId;
  5904. #else
  5905. DWORD OwnerId = 0;
  5906. #endif
  5907. DWORD ActFldLen;
  5908. JET_ERR JetRetStat;
  5909. BOOL fOnlyReplicas = FALSE;
  5910. BOOL fFirstIter = TRUE;
  5911. WINS_ASSIGN_INT_TO_VERS_NO_M(sHighestVersNoSaved, 0);
  5912. /*
  5913. * Set the primary index as the current index
  5914. */
  5915. CALL_M( JetSetCurrentIndex(
  5916. SesId,
  5917. TblId,
  5918. NMSDB_NAM_ADD_PRIM_INDEX_NAME
  5919. )
  5920. );
  5921. PERF("Remove this Move since when we set the index, we are automatically")
  5922. PERF("positioned on the first row")
  5923. //
  5924. // Move to the first record in the name - address mapping table
  5925. //
  5926. JetRetStat = JetMove(
  5927. SesId,
  5928. TblId,
  5929. JET_MoveFirst,
  5930. 0 //no grbit
  5931. );
  5932. //
  5933. // The following error indicates that either our database
  5934. // is empty or has garbage. I will assume for now that it
  5935. // is empty. If it contains garbage, we will know soon enough
  5936. //
  5937. if (JetRetStat == JET_errNoCurrentRecord)
  5938. {
  5939. FUTURES("Be more robust. Check if db contains garbage")
  5940. DBGPRINT0(ERR,
  5941. "GetMaxVersNos: There are no records in the db\n");
  5942. WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_NO_RECS_IN_NAM_ADD_TBL);
  5943. NmsDbNoOfOwners = 0;
  5944. return(WINS_SUCCESS);
  5945. }
  5946. CALL_M(JetRetStat);
  5947. //
  5948. // The fact that we are here means that there is atleast one record
  5949. // in our db
  5950. //
  5951. //
  5952. // Get the owner id and max version numbers of all owners in the
  5953. // table
  5954. //
  5955. do
  5956. {
  5957. //
  5958. // Retrieve the owner Id column.
  5959. //
  5960. CALL_M(
  5961. JetRetrieveColumn(
  5962. SesId,
  5963. TblId,
  5964. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  5965. &OwnerId,
  5966. NAM_ADD_OWNERID_SIZE,
  5967. &ActFldLen,
  5968. 0,
  5969. NULL
  5970. )
  5971. );
  5972. if (fFirstIter)
  5973. {
  5974. if (OwnerId != 0)
  5975. {
  5976. // The last owner id to be retrieved is not 0 means
  5977. // that there is no record owned by us
  5978. //
  5979. fOnlyReplicas = TRUE;
  5980. }
  5981. fFirstIter = FALSE;
  5982. }
  5983. //
  5984. // Specify an owner id that is 1 more than what we retrieved
  5985. //
  5986. OwnerId += 1;
  5987. // in case this is not the special record...
  5988. if ((OwnerId - 1) != OWNER_ID_OF_SPEC_REC)
  5989. {
  5990. // ...expand the ownerid - versNo array to at least OwnerId slots
  5991. if (RplPullMaxNoOfWins < OwnerId)
  5992. {
  5993. DWORD newMaxNoOfWins = max(RplPullMaxNoOfWins * 2, OwnerId);
  5994. RplPullAllocVersNoArray(&pRplPullOwnerVersNo, newMaxNoOfWins);
  5995. RplPullMaxNoOfWins = newMaxNoOfWins;
  5996. DBGPRINT1(DET, "ReadOwnAddTbl: No of slots in RPL_OWNER_VERS_NO_ARRAY has been increased to %d\n", RplPullMaxNoOfWins);
  5997. }
  5998. }
  5999. //
  6000. // Construct a partial key made of owner id.
  6001. //
  6002. CALL_M( JetMakeKey(
  6003. SesId,
  6004. TblId,
  6005. &OwnerId,
  6006. NAM_ADD_OWNERID_SIZE,
  6007. JET_bitNewKey //since this is the first
  6008. //data value of the key
  6009. )
  6010. );
  6011. //
  6012. // Seek to the record that has a key that is Less than or
  6013. // Equal to the OwnerId value.
  6014. //
  6015. // Since we have specified a partial key (saying in effect
  6016. // that the other component of the key is NULL), JetSeek
  6017. // must return wrnSeekNotEqual since it will never find
  6018. // a record with NULL for the second component of the index
  6019. // -- Ian 7/13/93
  6020. //
  6021. JetRetStat = JetSeek(
  6022. SesId,
  6023. TblId,
  6024. JET_bitSeekLE
  6025. );
  6026. ASSERT(JetRetStat == JET_wrnSeekNotEqual);
  6027. #ifdef WINSDBG
  6028. if (JetRetStat != JET_wrnSeekNotEqual)
  6029. {
  6030. DBGPRINT1(ERR, "GetMaxVersNos: JetSeek returned (%d)\n", JetRetStat);
  6031. }
  6032. #endif
  6033. //
  6034. // retrieve the version number of the record on which we
  6035. // are positioned. This is the max vers. number pertaining
  6036. // to OwnerId. If the Owner Id is one more than the
  6037. // owner id. we have assigned to the special record,
  6038. // then store the version number retrieved into
  6039. // sHighestVersNoSaved
  6040. //
  6041. CALL_M(
  6042. JetRetrieveColumn(
  6043. SesId,
  6044. TblId,
  6045. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  6046. ((OwnerId - 1 ) == OWNER_ID_OF_SPEC_REC) ?
  6047. &sHighestVersNoSaved :
  6048. &(pRplPullOwnerVersNo+OwnerId - 1)->VersNo,
  6049. sizeof(VERS_NO_T),
  6050. &ActFldLen,
  6051. 0,
  6052. NULL
  6053. )
  6054. );
  6055. if ((OwnerId - 1) == OWNER_ID_OF_SPEC_REC )
  6056. {
  6057. ASSERT(!sfHighestVersNoRecExists);
  6058. if (sfHighestVersNoRecExists)
  6059. {
  6060. DBGPRINT0(ERR, "GetMaxVersNo: ERROR: SOFTWARE BUG - Found both the old and new spec. owner id records. They are MUTUALLY EXCLUSIVE\n");
  6061. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
  6062. }
  6063. StoreSpecVersNo();
  6064. DBGPRINT3(INIT, "GetMaxVersNo: Owner Id - (%d) : Vers No. (%d %d)\n", (OwnerId - 1), sHighestVersNoSaved.HighPart, sHighestVersNoSaved.LowPart);
  6065. continue;
  6066. }
  6067. else
  6068. {
  6069. //
  6070. // If the owner id is == what used to be the owner id.
  6071. // of the special record, it means that we have a pre-SUR
  6072. // beta2 db. We should delete this name to get rid of
  6073. // clutter. We should mark the pRplPullOwnerVersNo slot
  6074. // empty since it was initialized above.
  6075. //
  6076. if ((OwnerId - 1) == OWNER_ID_OF_SPEC_REC_OLD )
  6077. {
  6078. LPBYTE Name[NMSDB_MAX_NAM_LEN];
  6079. DWORD NameLen;
  6080. //
  6081. // If the name is == spHighestVersNoRecNameOld, delete
  6082. // this record. This is the old special record
  6083. // we had. Save the vers. no. in a local
  6084. //
  6085. // NOTE: the length of the spec. rec. name is < 16
  6086. // bytes so it is not a valid netbios name
  6087. //
  6088. CALL_M( JetRetrieveColumn(
  6089. SesId,
  6090. TblId,
  6091. sNamAddTblRow[NAM_ADD_NAME_INDEX].Fid,
  6092. Name,
  6093. NMSDB_MAX_NAM_LEN,
  6094. &NameLen,
  6095. 0,
  6096. NULL));
  6097. if ((NameLen == sizeof(spHighestVersNoRecNameOld)) && RtlEqualMemory((PVOID)Name, spHighestVersNoRecNameOld, NameLen))
  6098. {
  6099. sHighestVersNoSaved =
  6100. (pRplPullOwnerVersNo+OwnerId - 1)->VersNo;
  6101. (pRplPullOwnerVersNo+OwnerId - 1)->VersNo.QuadPart = 0;
  6102. CALL_M(JetDelete(SesId, TblId));
  6103. StoreSpecVersNo();
  6104. DBGPRINT3(INIT, "GetMaxVersNo: Owner Id - (%d) : Vers No. (%d %d)\n", (OwnerId - 1), sHighestVersNoSaved.HighPart, sHighestVersNoSaved.LowPart);
  6105. continue;
  6106. }
  6107. }
  6108. }
  6109. DBGPRINT3(INIT, "GetMaxVersNo: Owner Id - (%d) : Vers No. (%d %d)\n", (OwnerId - 1), (pRplPullOwnerVersNo+OwnerId - 1)->VersNo.HighPart,
  6110. (pRplPullOwnerVersNo+OwnerId - 1)->VersNo.LowPart);
  6111. NmsDbNoOfOwners++; //count of owners found in the db
  6112. } while(
  6113. JetMove(SesId, TblId, JET_MoveNext, 0) == JET_errSuccess
  6114. );
  6115. //
  6116. // Check if the version counter's value is < that of the highest
  6117. // version found for owned records
  6118. // (found when we did the search in the while loop above. Use
  6119. // whichever is higher as the version counter)
  6120. //
  6121. if (!fOnlyReplicas)
  6122. {
  6123. //
  6124. // We need to increment the Vers. No. Counter to point to the
  6125. // number to be given to the next record
  6126. //
  6127. if (LiGeq(
  6128. pRplPullOwnerVersNo->VersNo,
  6129. NmsNmhMyMaxVersNo
  6130. )
  6131. )
  6132. {
  6133. //
  6134. // Initialize NmsNmhMyMaxVersNo. Remember this counter
  6135. // always contains the next version number to be given
  6136. // to a record. So, we must increment the count contained
  6137. // in RplPullOwnerVersNo[0] by 1
  6138. //
  6139. NMSNMH_INC_VERS_NO_M(
  6140. pRplPullOwnerVersNo->VersNo,
  6141. NmsNmhMyMaxVersNo
  6142. );
  6143. //
  6144. // Since we found records in the db, we take the conservative
  6145. // approach here, and set the Min Scv Vers. no to 1. If
  6146. // the first record has a very high version no. the scavenger
  6147. // thread will update the NmsScvMinVersNo to that value.
  6148. //
  6149. // We need to scavenge from this version onwards.
  6150. //
  6151. NmsScvMinScvVersNo.QuadPart = 1;
  6152. return(WINS_SUCCESS);
  6153. }
  6154. }
  6155. //
  6156. // Since we are here it means that when we searched for records
  6157. // belonging to the local WINS, we did not find any record
  6158. // We may or may not have found the special record. If we did find it
  6159. // it means that all the local records of the WINS were either
  6160. // deleted or replaced by replicas in its previous incarnation.
  6161. //
  6162. //
  6163. // If we found the special record, let us initialize RplPullOwnerVersNo
  6164. // entry for the local WINS
  6165. //
  6166. if (sfHighestVersNoRecExists)
  6167. {
  6168. pRplPullOwnerVersNo->VersNo = NmsNmhMyMaxVersNo;
  6169. //
  6170. // Increment the counter since it must always have a
  6171. // value to be given to the next local record we insert or
  6172. // update.
  6173. //
  6174. CHECK("May not be necessary")
  6175. NMSNMH_INC_VERS_NO_M(
  6176. NmsNmhMyMaxVersNo,
  6177. NmsNmhMyMaxVersNo
  6178. );
  6179. if (fOnlyReplicas)
  6180. {
  6181. //
  6182. // We need to scavenge from this version onwards.
  6183. //
  6184. NmsScvMinScvVersNo = NmsNmhMyMaxVersNo;
  6185. }
  6186. else
  6187. {
  6188. NmsScvMinScvVersNo.QuadPart = 1;
  6189. }
  6190. }
  6191. return(WINS_SUCCESS);
  6192. }
  6193. __inline
  6194. VOID
  6195. StoreSpecVersNo(
  6196. VOID
  6197. )
  6198. /*++
  6199. Routine Description:
  6200. This function conditionally updates NmsNmhMyMaxVersNo to a number that is 1
  6201. more than the version. no. found in the special owner id. record.
  6202. Arguments:
  6203. None
  6204. Externals Used:
  6205. NmsNmhMyMaxVersNo,
  6206. sfHighestVersNoExists
  6207. Return Value:
  6208. None
  6209. Error Handling:
  6210. Called by:
  6211. GetMaxVersNos()
  6212. Side Effects:
  6213. Comments:
  6214. None
  6215. --*/
  6216. {
  6217. sfHighestVersNoRecExists = TRUE;
  6218. //
  6219. // If the version counter's value is < that of
  6220. // the special record, update it.
  6221. //
  6222. //
  6223. // NOTE: If the registry specified a number for the
  6224. // version counter, then NmsNmhMyMaxVersNo would be
  6225. // having that value, else it would be 1
  6226. //
  6227. if (LiLtr(NmsNmhMyMaxVersNo, sHighestVersNoSaved))
  6228. {
  6229. NMSNMH_INC_VERS_NO_M( sHighestVersNoSaved, NmsNmhMyMaxVersNo);
  6230. }
  6231. return;
  6232. }
  6233. JET_ERR
  6234. InsertGrpMemsInCol(
  6235. JET_SESID SesId,
  6236. JET_TABLEID TblId,
  6237. PNMSDB_ROW_INFO_T pRowInfo,
  6238. ULONG TypOfUpd
  6239. )
  6240. /*++
  6241. Routine Description:
  6242. This function is called to insert members of a special group
  6243. in the address column field of the name - address mapping table
  6244. Arguments:
  6245. SesId - Session Id.
  6246. TblId - Table Id.
  6247. pRowInfo - Contains the member info
  6248. fOverwrite - Whether members in the list above would overwrite the
  6249. ones already there
  6250. Externals Used:
  6251. sNamAddTblRow
  6252. Return Value:
  6253. Success status codes -- JET_errSuccess
  6254. Error status codes -- Jet error codes
  6255. Error Handling:
  6256. Called by:
  6257. NmsDbRelRow, UpdateDb
  6258. Side Effects:
  6259. Comments:
  6260. None
  6261. --*/
  6262. {
  6263. JET_SETINFO SetInfo;
  6264. DWORD i;
  6265. JET_ERR JetRetStat = JET_errSuccess; //needs to be inited here
  6266. DBGENTER("InsertGrpMemsInCol\n");
  6267. SetInfo.itagSequence = 1; //has to be 1 always
  6268. SetInfo.ibLongValue = 0;
  6269. SetInfo.cbStruct = sizeof(JET_SETINFO);
  6270. ASSERT(pRowInfo->NodeAdds.NoOfMems <= NMSDB_MAX_MEMS_IN_GRP);
  6271. #ifdef WINSDBG
  6272. if (NMSDB_ENTRY_MULTIHOMED_M(pRowInfo->EntTyp) && pRowInfo->NodeAdds.NoOfMems > NMSDB_MAX_MEMS_IN_GRP)
  6273. {
  6274. DBGPRINT4(SPEC, "InsertGrpMemsInCol: Name is (%s); No Of Mems are (%d); Version number is (%d %d)\n", pRowInfo->pName, pRowInfo->NodeAdds.NoOfMems, pRowInfo->VersNo.HighPart, pRowInfo->VersNo.LowPart);
  6275. }
  6276. #endif
  6277. //
  6278. // Set the # of Members field. This is always the first
  6279. // field
  6280. //
  6281. if (TypOfUpd == JET_prepReplace)
  6282. {
  6283. // SetInfo.ibLongValue = sizeof(pRowInfo->NodeAdds.NoOfMems);
  6284. JETRET_M(JetSetColumn(
  6285. SesId,
  6286. TblId,
  6287. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  6288. NULL,
  6289. 0,
  6290. JET_bitSetSizeLV,
  6291. &SetInfo /*optional info */
  6292. )
  6293. );
  6294. // SetInfo.ibLongValue = 0;
  6295. }
  6296. JETRET_M(JetSetColumn(
  6297. SesId,
  6298. TblId,
  6299. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  6300. &pRowInfo->NodeAdds.NoOfMems,
  6301. sizeof(pRowInfo->NodeAdds.NoOfMems),
  6302. JET_bitSetAppendLV,
  6303. &SetInfo /*optional info */
  6304. )
  6305. );
  6306. for (
  6307. i=0;
  6308. i < pRowInfo->NodeAdds.NoOfMems && JetRetStat == JET_errSuccess;
  6309. i++
  6310. )
  6311. {
  6312. DBGPRINT3(DET, "InsertGrpMemsInCol: Inserted member (%d) with address (%X) and owner id (%d)\n", i, pRowInfo->NodeAdds.Mem[i].Add.Add.IPAdd,
  6313. pRowInfo->NodeAdds.Mem[i].OwnerId
  6314. );
  6315. CHECK("Check this on a MIPS machine")
  6316. //
  6317. // Set the GrpMem
  6318. //
  6319. JetRetStat = JetSetColumn(
  6320. SesId,
  6321. TblId,
  6322. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  6323. &pRowInfo->NodeAdds.Mem[i],
  6324. sizeof(NMSDB_GRP_MEM_ENTRY_T),
  6325. JET_bitSetAppendLV,
  6326. // TypOfUpd == JET_prepReplace ? JET_bitSetOverwriteLV : JET_bitSetAppendLV,
  6327. &SetInfo /*optional info */
  6328. );
  6329. } // end of for
  6330. DBGLEAVE("InsertGrpMemsInCol\n");
  6331. return(JetRetStat);
  6332. }
  6333. STATUS
  6334. NmsDbSetCurrentIndex(
  6335. IN NMSDB_TBL_NAM_E TblNm_e,
  6336. IN LPBYTE pIndexNam
  6337. )
  6338. /*++
  6339. Routine Description:
  6340. This function is called to set the index on a table
  6341. Arguments:
  6342. TblNm_e - Identifies the table whose index needs to be set
  6343. pIndexNm - Name of index to be set
  6344. Externals Used:
  6345. None
  6346. Return Value:
  6347. Success status codes -- WINS_SUCCESS
  6348. Error status codes -- WINS_FAILURE
  6349. Error Handling:
  6350. Called by:
  6351. Side Effects:
  6352. Comments:
  6353. None
  6354. --*/
  6355. {
  6356. PWINSTHD_TLS_T pTls;
  6357. GET_TLS_M(pTls);
  6358. ASSERT(pTls != NULL);
  6359. /*
  6360. * Use primary index now
  6361. */
  6362. CALL_M( JetSetCurrentIndex(
  6363. pTls->SesId,
  6364. TblNm_e == NMSDB_E_NAM_ADD_TBL_NM ?
  6365. pTls->NamAddTblId :
  6366. pTls->OwnAddTblId,
  6367. pIndexNam
  6368. )
  6369. );
  6370. return(WINS_SUCCESS);
  6371. }
  6372. STATUS
  6373. NmsDbQueryNUpdIfMatch(
  6374. LPVOID pRecord,
  6375. int ThdPrLvl,
  6376. BOOL fChgPrLvl,
  6377. WINS_CLIENT_E Client_e
  6378. )
  6379. /*++
  6380. Routine Description:
  6381. This function is called to query a record and then update it only
  6382. if it matches the timestamp of the record supplied
  6383. Arguments:
  6384. pRecord - Record supplied
  6385. ThdPrLvl - Priority level of the thread
  6386. fChgPrLvl - TRUE, if priority level of the thread needs to be changed
  6387. Externals Used:
  6388. None
  6389. Return Value:
  6390. Success status codes -- WINS_SUCCESS
  6391. Error status codes -- WINS_FAILURE
  6392. Error Handling:
  6393. Called by:
  6394. UpdDb in nmsscv.c, WinsRecordAction in winsintf.c
  6395. Side Effects:
  6396. Comments:
  6397. This function must be called only when the index on the name
  6398. address table has been set to the clustered index column.
  6399. --*/
  6400. {
  6401. BYTE State;
  6402. DWORD TimeStamp = 0;
  6403. DWORD ActFldLen;
  6404. JET_TABLEID TblId;
  6405. JET_SESID SesId;
  6406. PWINSTHD_TLS_T pTls;
  6407. PRPL_REC_ENTRY_T pRec = pRecord;
  6408. JET_ERR JetRetStat;
  6409. BOOL fIncVersNo = FALSE;
  6410. #if NEW_OWID
  6411. DWORD OwnerId;
  6412. #else
  6413. DWORD OwnerId = 0;
  6414. #endif
  6415. BOOL fAbort = FALSE;
  6416. DBGENTER("NmsDbQueryNUpdIfMatch\n");
  6417. GET_TLS_M(pTls);
  6418. ASSERT(pTls != NULL);
  6419. TblId = pTls->NamAddTblId;
  6420. SesId = pTls->SesId;
  6421. State = (BYTE)NMSDB_ENTRY_STATE_M(pRec->Flag);
  6422. #if 0
  6423. NmsDbSetCurrentIndex(
  6424. NMSDB_E_NAM_ADD_TBL_NM,
  6425. NMSDB_NAM_ADD_CLUST_INDEX_NAME
  6426. );
  6427. #endif
  6428. //
  6429. // Make sure you enter the critical section
  6430. // prior to deleting a record. This is because
  6431. // another thread may be seeking to it after
  6432. // conflicting with it. If we delete the
  6433. // record without entering the critical
  6434. // section, the thread may not
  6435. // find the record. This would cause it to
  6436. // raise an exception.
  6437. //
  6438. if (fChgPrLvl)
  6439. {
  6440. //
  6441. // Set the priority to NORMAL. We
  6442. // don't want to delay normal
  6443. // priority threads by getting
  6444. // starved of cpu time inside
  6445. // the critical section.
  6446. //
  6447. WinsMscSetThreadPriority(
  6448. WinsThdPool.ScvThds[0].ThdHdl,
  6449. THREAD_PRIORITY_NORMAL
  6450. );
  6451. }
  6452. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  6453. try {
  6454. //
  6455. // Seek to the record
  6456. //
  6457. CALL_M( JetMakeKey(
  6458. SesId,
  6459. TblId,
  6460. // pRec->Name,
  6461. pRec->pName,
  6462. pRec->NameLen,
  6463. JET_bitNewKey
  6464. )
  6465. );
  6466. if (JetSeek(
  6467. SesId,
  6468. TblId,
  6469. JET_bitSeekEQ
  6470. ) == JET_errSuccess
  6471. )
  6472. {
  6473. BOOL fUpdSpecRec = FALSE;
  6474. VERS_NO_T RecVersNo;
  6475. VERS_NO_T MyMaxVersNo;
  6476. //
  6477. // If we are doing scavenging, we need to make sure that
  6478. // while we were examining the records, the record that
  6479. // we want to update now, did not get updated. To check
  6480. // that we retrieve the timestamp of the record
  6481. //
  6482. if (Client_e == WINS_E_NMSSCV)
  6483. {
  6484. //
  6485. // retrieve the time stamp
  6486. //
  6487. CALL_M( JetRetrieveColumn(
  6488. SesId,
  6489. TblId,
  6490. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  6491. &TimeStamp,
  6492. sizeof(TimeStamp),
  6493. &ActFldLen,
  6494. 0,
  6495. NULL
  6496. )
  6497. );
  6498. }
  6499. //
  6500. // if timestamp is the same, we have our record.
  6501. // we don't need to check any other field. Exception: If we
  6502. // are an RPC thread, whether or not we update the
  6503. // record is independent of the timestamp that the
  6504. // record may have now
  6505. //
  6506. if (
  6507. (pRec->TimeStamp == TimeStamp)
  6508. ||
  6509. (Client_e == WINS_E_WINSRPC)
  6510. )
  6511. {
  6512. //
  6513. // if state of the record is deleted, we need to
  6514. // delete it from the database.
  6515. //
  6516. if (State == NMSDB_E_DELETED)
  6517. {
  6518. //
  6519. // If Client is an RPC thread, first retrieve
  6520. // the owner id and version number of the
  6521. // record to delete
  6522. //
  6523. if (Client_e == WINS_E_WINSRPC)
  6524. {
  6525. CALL_M( JetRetrieveColumn(
  6526. SesId,
  6527. TblId,
  6528. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  6529. &OwnerId,
  6530. NAM_ADD_OWNERID_SIZE,
  6531. &ActFldLen,
  6532. 0,
  6533. NULL
  6534. )
  6535. );
  6536. if (OwnerId == NMSDB_LOCAL_OWNER_ID)
  6537. {
  6538. //
  6539. // Retrieve the version number
  6540. //
  6541. CALL_M( JetRetrieveColumn(
  6542. SesId,
  6543. TblId,
  6544. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  6545. &RecVersNo,
  6546. sizeof(VERS_NO_T),
  6547. &ActFldLen,
  6548. 0,
  6549. NULL
  6550. )
  6551. );
  6552. //
  6553. // get the highest version number used
  6554. // up until now.
  6555. //
  6556. NMSNMH_DEC_VERS_NO_M(NmsNmhMyMaxVersNo,
  6557. MyMaxVersNo);
  6558. //
  6559. // If the record to be deleted has
  6560. // the this highest version number we
  6561. // must update the special record
  6562. //
  6563. if(LiEql(RecVersNo, MyMaxVersNo))
  6564. {
  6565. fUpdSpecRec = TRUE;
  6566. }
  6567. }
  6568. }
  6569. CALL_M(JetDelete(
  6570. SesId,
  6571. TblId
  6572. )
  6573. );
  6574. #ifdef WINSDBG
  6575. NmsDbDelQueryNUpdRecs++;
  6576. #endif
  6577. DBGPRINT2(SCV, "NmsDbQueryNUpdIfMatch: Deleted the record with name = (%s);16th char (%X)\n", pRec->pName, *(pRec->pName + 15));
  6578. //
  6579. // This can be TRUE only in an RPC thread
  6580. //
  6581. if (fUpdSpecRec)
  6582. {
  6583. NmsDbUpdHighestVersNoRec(
  6584. pTls,
  6585. MyMaxVersNo,
  6586. FALSE //don't enter Crt
  6587. //sec
  6588. );
  6589. }
  6590. }
  6591. else // we need to set the Flag field and in the
  6592. //case of a tombstone record update the version
  6593. //stamp
  6594. {
  6595. CALL_M(JetBeginTransaction(SesId));
  6596. try {
  6597. JetRetStat = JetPrepareUpdate(
  6598. SesId,
  6599. TblId,
  6600. JET_prepReplace
  6601. );
  6602. if (
  6603. (JetRetStat != JET_errSuccess)
  6604. &&
  6605. (JetRetStat != JET_wrnNoWriteLock)
  6606. )
  6607. {
  6608. FUTURES("When Jet becomes stable, replace RET_M with a raise_exception")
  6609. //
  6610. // this should result in the execution
  6611. // of the finally clause
  6612. //
  6613. RET_M(JetRetStat);
  6614. }
  6615. if (Client_e == WINS_E_WINSRPC)
  6616. {
  6617. DWORD FlagVal;
  6618. BYTE EntryType;
  6619. BYTE NewEntryType;
  6620. //
  6621. // Retrieve the flags byte
  6622. //
  6623. // retrieve the flags column
  6624. CALL_M( JetRetrieveColumn(
  6625. SesId,
  6626. TblId,
  6627. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  6628. &FlagVal,
  6629. sizeof(FlagVal),
  6630. &ActFldLen,
  6631. 0,
  6632. NULL
  6633. )
  6634. );
  6635. EntryType = (BYTE)NMSDB_ENTRY_TYPE_M(FlagVal);
  6636. NewEntryType = (BYTE)NMSDB_ENTRY_TYPE_M(pRec->Flag);
  6637. //
  6638. // A unique/normal group record
  6639. // can not be changed to a multihomed/
  6640. // special group record unless the
  6641. // address column too is changed
  6642. //
  6643. if (
  6644. (
  6645. (
  6646. EntryType == NMSDB_UNIQUE_ENTRY
  6647. ||
  6648. EntryType ==
  6649. NMSDB_NORM_GRP_ENTRY
  6650. )
  6651. &&
  6652. (
  6653. NewEntryType ==
  6654. NMSDB_SPEC_GRP_ENTRY
  6655. ||
  6656. NewEntryType ==
  6657. NMSDB_MULTIHOMED_ENTRY
  6658. )
  6659. )
  6660. ||
  6661. (
  6662. (
  6663. EntryType ==
  6664. NMSDB_SPEC_GRP_ENTRY
  6665. ||
  6666. EntryType ==
  6667. NMSDB_MULTIHOMED_ENTRY
  6668. )
  6669. &&
  6670. (
  6671. NewEntryType == NMSDB_UNIQUE_ENTRY
  6672. ||
  6673. NewEntryType ==
  6674. NMSDB_NORM_GRP_ENTRY
  6675. )
  6676. )
  6677. )
  6678. {
  6679. DBGPRINT0(ERR, "NmsDbQueryNUpdIfMatch: SORRY, Can not change to an incompatibe address format record. (Unique/Normal Group) to (Multihomed/Spec. Group) or vice-versa disallowed\n");
  6680. PERF("Do not return like this. finally block search is expensive")
  6681. fAbort = TRUE;
  6682. return(WINS_FAILURE);
  6683. }
  6684. } // end of if (client is RPC)
  6685. //
  6686. // Update the flags field
  6687. //
  6688. CALL_M( JetSetColumn(
  6689. SesId,
  6690. TblId,
  6691. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  6692. &pRec->Flag,
  6693. sizeof(pRec->Flag),
  6694. 0,
  6695. NULL /*optional info */
  6696. )
  6697. );
  6698. /* Update the timestamp column */
  6699. CALL_M( JetSetColumn(
  6700. SesId,
  6701. TblId,
  6702. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  6703. &(pRec->NewTimeStamp),
  6704. sizeof(DWORD), /*change type
  6705. *to
  6706. *TIME_STAMP_T
  6707. *later
  6708. */
  6709. 0,
  6710. NULL /*optional info */
  6711. )
  6712. );
  6713. //
  6714. // If the state of the record is a Tombstone
  6715. // or ACTIVE, we need to update the version
  6716. // number.
  6717. //
  6718. if (
  6719. (State == NMSDB_E_TOMBSTONE)
  6720. ||
  6721. (State == NMSDB_E_ACTIVE)
  6722. )
  6723. {
  6724. VERS_NO_T VersNo;
  6725. VersNo = NmsNmhMyMaxVersNo;
  6726. //
  6727. // Make local WINS the owner if
  6728. // we are in an RPC thread. We
  6729. // have to make the local WINS the
  6730. // owner in order to update the
  6731. // version stamp. Also, note that if
  6732. // this is not the RPC thread then
  6733. // this has to be the scavenger thread
  6734. // (FYI: A scavenger thread never
  6735. // changes a replica into a tombstone)
  6736. //
  6737. if (Client_e == WINS_E_WINSRPC)
  6738. {
  6739. DWORD OwnerId=NMSDB_LOCAL_OWNER_ID;
  6740. /* Set the owner byte */
  6741. CALL_M( JetSetColumn(
  6742. SesId,
  6743. TblId,
  6744. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  6745. &OwnerId,
  6746. NAM_ADD_OWNERID_SIZE,
  6747. 0,
  6748. NULL /*optional info */
  6749. )
  6750. );
  6751. //
  6752. // Update the version number field
  6753. // so that this record gets
  6754. // propagated eventually
  6755. //
  6756. CALL_M( JetSetColumn(
  6757. SesId,
  6758. TblId,
  6759. sNamAddTblRow[
  6760. NAM_ADD_VERSIONNO_INDEX].Fid,
  6761. &VersNo,
  6762. sizeof(VERS_NO_T),
  6763. 0,
  6764. NULL /*optional info */
  6765. )
  6766. );
  6767. fIncVersNo = TRUE;
  6768. }
  6769. else
  6770. {
  6771. //
  6772. // This is the scavenger thread.
  6773. // If the new state is not ACTIVE,
  6774. // update the version number since
  6775. // the state is TOMBSTONE.
  6776. // if the state is ACTIVE, then it
  6777. // means that we are doing a
  6778. // a revalidation of old replicas
  6779. // (i,e, the VerifyClutter() called
  6780. // us).
  6781. // The version number should stay
  6782. // the same.
  6783. //
  6784. if (State != NMSDB_E_ACTIVE)
  6785. {
  6786. // if the current record is replica dont touch
  6787. // the version #.
  6788. CALL_M( JetRetrieveColumn(
  6789. SesId,
  6790. TblId,
  6791. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  6792. &OwnerId,
  6793. NAM_ADD_OWNERID_SIZE,
  6794. &ActFldLen,
  6795. 0,
  6796. NULL));
  6797. if (NMSDB_LOCAL_OWNER_ID == OwnerId) {
  6798. //
  6799. // Update the version number field
  6800. //
  6801. CALL_M( JetSetColumn(
  6802. SesId,
  6803. TblId,
  6804. sNamAddTblRow[
  6805. NAM_ADD_VERSIONNO_INDEX].Fid,
  6806. &VersNo,
  6807. sizeof(VERS_NO_T),
  6808. 0,
  6809. NULL /*optional info */
  6810. )
  6811. );
  6812. fIncVersNo = TRUE;
  6813. }
  6814. }
  6815. }
  6816. } // if (state is ACTIVE or TOMBSTONE)
  6817. //
  6818. // Update the record
  6819. //
  6820. CALL_M(JetUpdate (
  6821. SesId,
  6822. TblId,
  6823. NULL,
  6824. 0L,
  6825. NULL
  6826. )
  6827. );
  6828. } // end of try block
  6829. finally {
  6830. if (AbnormalTermination())
  6831. {
  6832. // if there is an abnormal termination, we already have an error
  6833. // code here. We shouldn't override it with any other error code.
  6834. JetRollback(SesId, JET_bitRollbackAll);
  6835. }
  6836. else
  6837. {
  6838. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  6839. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  6840. CALL_M(JetCommitTransaction(SesId,
  6841. JET_bitCommitFlush));
  6842. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  6843. }
  6844. }
  6845. if (fIncVersNo)
  6846. {
  6847. NMSNMH_INC_VERS_COUNTER_M(
  6848. NmsNmhMyMaxVersNo,
  6849. NmsNmhMyMaxVersNo
  6850. );
  6851. RPL_PUSH_NTF_M(
  6852. RPL_PUSH_NO_PROP, NULL, NULL, NULL);
  6853. }
  6854. } // New state is not DELETED
  6855. } // if (Timestamps equal or client is RPC)
  6856. #ifdef WINSDBG
  6857. else
  6858. {
  6859. DBGPRINT0(FLOW, "NmsDbQueryNUpdIfMatch: TimeStamp of record has changed\n");
  6860. }
  6861. #endif
  6862. }
  6863. else //seek failed
  6864. {
  6865. DBGPRINT3(FLOW, "NmsDbQueryNUpdIfMatch: Could not find record(%s[%x]) whose state has to be changed to (%d)\n",
  6866. pRec->pName, *(pRec->pName + 15),
  6867. NMSDB_ENTRY_STATE_M(pRec->Flag));
  6868. //
  6869. // Two different threads (RPC or Scavenger) can be calling
  6870. // this function. It is possible that either might have
  6871. // deleted the record. We should not raise an exception
  6872. // here
  6873. //
  6874. // WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
  6875. }
  6876. } // end of try { ..}
  6877. finally {
  6878. if (AbnormalTermination() && !fAbort)
  6879. {
  6880. DBGPRINT0(ERR, "NmsDbQueryNUpdIfMatch: Abnormal Termination\n");
  6881. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
  6882. }
  6883. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  6884. if (fChgPrLvl)
  6885. {
  6886. WinsMscSetThreadPriority(
  6887. WinsThdPool.ScvThds[0].ThdHdl,
  6888. ThdPrLvl
  6889. );
  6890. }
  6891. } //end of finally
  6892. DBGLEAVE("NmsDbQueryNUpdIfMatch\n");
  6893. return(WINS_SUCCESS);
  6894. } // NmsDbQueryNUpdIfMatch
  6895. STATUS
  6896. SetSystemParamsJet600(
  6897. BOOL fBeforeInit
  6898. )
  6899. /*++
  6900. Routine Description:
  6901. This function is called to set the system parameters for Jet
  6902. Arguments:
  6903. fBeforeInit - indicates whether this function has been called
  6904. prior to JetInit
  6905. Externals Used:
  6906. None
  6907. Return Value:
  6908. Success status codes --
  6909. Error status codes --
  6910. --*/
  6911. {
  6912. JET_ERR JetRetStat;
  6913. BOOL fFreeMem = TRUE;
  6914. CHAR DbFileDir[WINS_MAX_FILENAME_SZ]; //path to database file directory
  6915. DBGENTER("SetSystemParam600\n");
  6916. if (fBeforeInit)
  6917. {
  6918. CHAR *p;
  6919. // extract the directory path where database file will be created
  6920. strcpy(DbFileDir, WinsCnf.pWinsDb);
  6921. if (p = strrchr(DbFileDir, '\\')) {
  6922. p++ ;
  6923. *p = '\0';
  6924. } else {
  6925. return WINS_FAILURE;
  6926. }
  6927. //
  6928. // set this to enable version checking.
  6929. //
  6930. CALL_M(JetSetSystemParameter(
  6931. &sJetInstance,
  6932. (JET_SESID)0, //SesId - ignored
  6933. JET_paramCheckFormatWhenOpenFail,
  6934. 1,
  6935. NULL
  6936. )
  6937. );
  6938. CALL_M(JetSetSystemParameter(
  6939. &sJetInstance,
  6940. (JET_SESID)0, //SesId - ignored
  6941. JET_paramExceptionAction,
  6942. JET_ExceptionMsgBox,
  6943. NULL
  6944. )
  6945. );
  6946. //
  6947. // Path for the checkpoint file jet.chk to be located
  6948. //
  6949. CALL_M(JetSetSystemParameter(
  6950. &sJetInstance,
  6951. (JET_SESID)0, //SesId - ignored
  6952. JET_paramSystemPath,
  6953. 0,
  6954. DbFileDir
  6955. )
  6956. );
  6957. //
  6958. // Basename to use for jet*.log and jet.chk
  6959. //
  6960. CALL_M(JetSetSystemParameter(
  6961. &sJetInstance,
  6962. (JET_SESID)0, //SesId - ignored
  6963. JET_paramBaseName,
  6964. 0,
  6965. BASENAME
  6966. )
  6967. );
  6968. //
  6969. // Max size of the log file in kb.
  6970. //
  6971. CALL_M(JetSetSystemParameter(
  6972. &sJetInstance,
  6973. (JET_SESID)0, //SesId - ignored
  6974. JET_paramLogFileSize,
  6975. 1024, //set to one full meg (#96543)
  6976. NULL //ignored
  6977. )
  6978. );
  6979. CALL_M(JetSetSystemParameter(
  6980. &sJetInstance,
  6981. (JET_SESID)0, //SesId - ignored
  6982. JET_paramTempPath,
  6983. 0,
  6984. TEMP_DB_PATH //ignored
  6985. )
  6986. );
  6987. PERF("Check the following two things")
  6988. //
  6989. // We want some aggressive flushing. The performance impact
  6990. // is very trivial - Ian Jose 7/12/93
  6991. //
  6992. //
  6993. // The max number of buffers for database usage
  6994. //
  6995. // The default number is 500. 600 events are allocated
  6996. // for 500 buffers -- Ian 10/21/93. Each buffer is
  6997. // 4K. By keeping the number small, we impact performamce
  6998. //
  6999. CALL_M(JetSetSystemParameter(
  7000. &sJetInstance,
  7001. (JET_SESID)0, //SesId - ignored
  7002. JET_paramCacheSizeMax, // JET_paramMaxBuffers,
  7003. WinsCnf.NoOfDbBuffers,//200,
  7004. NULL //ignored
  7005. )
  7006. );
  7007. // Cheen: min cache size should be at-least 4 times the size of no of sessions
  7008. // o/w it can lead to deadlock.
  7009. ASSERT( WinsCnf.NoOfDbBuffers > MAX_NO_SESSIONS*4 );
  7010. CALL_M(JetSetSystemParameter(
  7011. &sJetInstance,
  7012. (JET_SESID)0, //SesId - ignored
  7013. JET_paramCacheSizeMin,
  7014. MAX_NO_SESSIONS * 4,
  7015. NULL //ignored
  7016. )
  7017. );
  7018. //
  7019. // The max. number of buffers to store old version of a
  7020. // a record (snapshot at the start of a transaction)
  7021. // Each version store is 16k bytes. A version store
  7022. // stores structures that hold information derived from
  7023. // a snapshot of the database prior to an insert (20 bytes
  7024. // roughly) or update (size of the record + 20 bytes).
  7025. //
  7026. // For small transactions (i.e. a transaction around each
  7027. // update), this number should be >= the max. number of
  7028. // sessions that can be updating/inserting at the same time.
  7029. // Each session will have one version bucket. Since 16k of
  7030. // version bucket size can result in a lot of wastage per
  7031. // session (since each record is < .5k, and on the average
  7032. // around 50 bytes), it may be better to specify the
  7033. // max. size of the version bucket (<< 16k). Ian will
  7034. //provide a system param for this if we absolutely need it
  7035. //
  7036. // 3/4/93
  7037. //16kBytes should be enough for the transactions WINS does,
  7038. //but if all the sessions are in transactions at the same time
  7039. //and they all happen to have their small transactions traverse
  7040. //2 buckets then the peak requirement is 2 buckets per session.
  7041. //We could shorten the buckets to 8kBytes, or 4kBytes, and you
  7042. //could allocate 2 per session?
  7043. //
  7044. // 8/5/99
  7045. // The previous value was 16M (42x15 pages of 16K each ~= 16M).
  7046. // This value seems to be a bit too small so bump it to 32M.
  7047. CALL_M(JetSetSystemParameter(
  7048. &sJetInstance,
  7049. (JET_SESID)0, //SesId - ignored
  7050. JET_paramMaxVerPages,
  7051. MAX_NO_SESSIONS * 50, //number of 16K pages
  7052. NULL //ignored
  7053. )
  7054. );
  7055. //
  7056. // Set the File Control Block Param
  7057. //
  7058. // This is the max. number of tables that can be open
  7059. // at any time. If multiple threads open the same table
  7060. // they use the same FCB. FCB is 1 per table/index.
  7061. // Now, for a create database, we need atleast 18 FCBS
  7062. // and 18 IDBS. However apart from create database and
  7063. // ddl operations, we don't need to have these tables open.
  7064. // Default value is 300. Size of an FCB is 112 bytes.
  7065. //
  7066. // Jonathan Liem (1/6/97)
  7067. // JET_paramMaxOpenTableIndexes is removed. It is merged with
  7068. // JET_paramMaxOpenTables. So if you used to set JET_paramMaxOpenIndexes
  7069. // to be 2000 and JET_paramMaxOpenTables to be 1000, then for
  7070. // new Jet, you need to set JET_paramMaxOpenTables to 3000.
  7071. //
  7072. CALL_M(JetSetSystemParameter(
  7073. &sJetInstance,
  7074. (JET_SESID)0, //SesId - ignored
  7075. JET_paramMaxOpenTables,
  7076. 112, //was 56 //18 + 10,
  7077. NULL //ignored
  7078. )
  7079. );
  7080. //
  7081. // Set the File Usage Control Block to 100.
  7082. // This parameter indicates the max. number of cursors
  7083. // that can be open at any one time. This is
  7084. // therefore dependent on the the max. number of sessions
  7085. // that we can have running concurrently. For each session,
  7086. // there would be 4 cursors (for the two tables) + a certain
  7087. // number of internal cursors. For good measure we add
  7088. // a pad. Default value is 300. Size of each is 200 bytes.
  7089. // We use MAX_SESSIONS * 4 + pad
  7090. // (around 100)
  7091. //
  7092. CALL_M(JetSetSystemParameter(
  7093. &sJetInstance,
  7094. (JET_SESID)0, //SesId - ignored
  7095. JET_paramMaxCursors,
  7096. (MAX_NO_SESSIONS * 8 /*4*/) + 32,
  7097. NULL //ignored
  7098. )
  7099. );
  7100. //
  7101. // Set the Sort Control block.
  7102. // This should be 1 per concurrent Create Index.
  7103. // Default value is 20. Size of each is 612 bytes.
  7104. // In the case of WINS, the main thread creates the
  7105. // indices. We should be setting it to 1. Let us
  7106. // however set it to 3.
  7107. //
  7108. CALL_M(JetSetSystemParameter(
  7109. &sJetInstance,
  7110. (JET_SESID)0, //SesId - ignored
  7111. JET_paramMaxTemporaryTables ,
  7112. 10, //1 + 2,
  7113. NULL //ignored
  7114. )
  7115. );
  7116. //
  7117. // Set the Number for the Database Attribute Blocks
  7118. //
  7119. // This is max. number of Open Databases done. Since we
  7120. // can have a max of MAX_NO_SESSIONS at one time. This should
  7121. // be equal to that number (since we have just one database)
  7122. // Default number is 100. Size is 14 bytes
  7123. //
  7124. // JET_paramMaxOpenDatabase is removed. Jonathan Liem (1/6/97)
  7125. // Jonathan Liem (1/6/97)
  7126. // JET_paramBfThrshldLowPrcnt and JET_paramBfThrhldHighPrcnt are changed
  7127. // to JET_paramStartFlushThreshold and JET_paramStopFlushThreshold. The
  7128. // old ones are percent of given number of buffers (set through JET_paramMaxBuffer),
  7129. // the new ones are absolute value so that we can set low threshold less
  7130. // than 1 percent.
  7131. //
  7132. //
  7133. // The min number of buffers not yet dirtied before
  7134. // background flushing begins
  7135. //
  7136. CALL_M(JetSetSystemParameter(
  7137. &sJetInstance,
  7138. (JET_SESID)0, //SesId - ignored
  7139. JET_paramStartFlushThreshold,
  7140. (WinsCnf.NoOfDbBuffers * 1)/100,
  7141. NULL //ignored
  7142. )
  7143. );
  7144. //
  7145. // The max number of buffers not yet dirtied before
  7146. // background flushing begins
  7147. //
  7148. CALL_M(JetSetSystemParameter(
  7149. &sJetInstance,
  7150. (JET_SESID)0, //SesId - ignored
  7151. JET_paramStopFlushThreshold,
  7152. (WinsCnf.NoOfDbBuffers * 2)/100,
  7153. NULL //ignored
  7154. )
  7155. );
  7156. //
  7157. // The max. number of sessions that can be open at any time
  7158. //
  7159. // Note: Jet does not preallocate resources corresponding
  7160. // to the max. value. It allocates them dynamically upto
  7161. // the limit -- according to Ian Jose 7/12/93
  7162. //
  7163. // When checked with Ian again on 10/21, he said that they are
  7164. // allocated STATICally
  7165. //
  7166. CHECK("Make sure the comment above remains true")
  7167. FUTURES("Make sure the comment above remains true")
  7168. CALL_M(JetSetSystemParameter(
  7169. &sJetInstance,
  7170. (JET_SESID)0, //SesId - ignored
  7171. JET_paramMaxSessions,
  7172. MAX_NO_SESSIONS,
  7173. NULL //ignored
  7174. )
  7175. );
  7176. // don't playback old logs upon restore (bug #277816)
  7177. CALL_M(JetSetSystemParameter(
  7178. &sJetInstance,
  7179. (JET_SESID)0,
  7180. JET_paramDeleteOutOfRangeLogs,
  7181. 1,
  7182. NULL));
  7183. //
  7184. // Turn on logging if not prohibited by administrator
  7185. //
  7186. if (WinsCnf.fLoggingOn)
  7187. {
  7188. // enable circular logging
  7189. CALL_M(JetSetSystemParameter(
  7190. &sJetInstance,
  7191. (JET_SESID)0,
  7192. JET_paramCircularLog,
  7193. 1,
  7194. NULL));
  7195. FUTURES("Internationalize the following when jet is internationalized")
  7196. //
  7197. // Turn logging (recovery) on
  7198. //
  7199. CALL_M(JetSetSystemParameter(
  7200. &sJetInstance,
  7201. (JET_SESID)0, //SesId - ignored
  7202. JET_paramRecovery,
  7203. 0, //ignored
  7204. "on"
  7205. )
  7206. );
  7207. //
  7208. // The number of log sectors. Each sector is
  7209. // 512 bytes. We should keep the size more than
  7210. // the threshold so that if the threshold is reached
  7211. // and flushing starts, Jet can still continue to
  7212. // log in the spare sectors. Point to note is that
  7213. // if the log rate is faster than the flush rate, then
  7214. // the Jet engine thread will not be able to log when
  7215. // the entire buffer is filled up. It will then wait
  7216. // until space becomes available.
  7217. //
  7218. CALL_M(JetSetSystemParameter(
  7219. &sJetInstance,
  7220. (JET_SESID)0, //SesId - ignored
  7221. JET_paramLogBuffers,
  7222. 30, //30 sectors
  7223. NULL //ignored
  7224. )
  7225. );
  7226. //
  7227. // Set the number of log buffers dirtied before they
  7228. // are flushed. This number should always be less than
  7229. // the number for LogBuffers so that spare sectors
  7230. // are there for concurrent logging. Also, we should
  7231. // make this number high enough to handle burst of
  7232. // traffic.
  7233. //
  7234. // this is gone in jet600.dll cheen liao 1/6/96
  7235. //
  7236. // Set the wait time (in msecs) to wait prior to
  7237. // flushing the log on commit transaction to allow
  7238. // other users (sessions) to share the flush
  7239. //
  7240. //
  7241. // This is the time after which the user (a session)
  7242. // will ask the log manager to flush. If we specify
  7243. // 0 here than it means flush every time a transaction
  7244. // commits. In the WINS server case, every insertion
  7245. // or modification is done under an implicit
  7246. // transaction. So, it means that there will be
  7247. // a flush after every such transaction. It has
  7248. // been seen on a 486/66 (Cheen Liao) machine that
  7249. // it takes roughly 16 msecs to do the flush. The
  7250. // time it takes to do the flush is dependent upon
  7251. // the type of disk (how fast it is), the CPU speed,
  7252. // the type of file system etc. We can for now
  7253. // go with the assumption that it is in the range
  7254. // 15-25 msecs. I am pushing for this WaitTime to
  7255. // be made a session specific param so that it can
  7256. // be changed on the fly if the admin. finds that
  7257. // the WINS server is slow due to the WaitTime being
  7258. // very low or if it finds it to be so large that
  7259. // in case of a crash, there is possibility to loose
  7260. // a lot of data.
  7261. //
  7262. // Making this session specific is also very important
  7263. // for replication where we do want to set it to
  7264. // a high value (high enough to ensure that most
  7265. // of the records that need to be inserted are
  7266. // inserted before a flush action takes place. The
  7267. // wait time would be set every time a bunch of
  7268. // records are pulled in for replication. It will
  7269. // be computed based on the number of records pulled
  7270. // in and the time it takes to insert one record in the
  7271. // jet buffer. The wait time should preferably be < than
  7272. // the above computed time (it does not have to be).
  7273. //
  7274. // NOTE: In the Pull thread, I will need to start
  7275. // two sessions, one for updating the OwnerId-Version
  7276. // number table (0 wait time) and the other to
  7277. // update the name-address mapping table (wait time
  7278. // computed based on the factors mentioned above)
  7279. //
  7280. // The following will set the WaitLogFlush time for
  7281. // all sessions.
  7282. //
  7283. CALL_M(JetSetSystemParameter(
  7284. &sJetInstance,
  7285. (JET_SESID)0, //SesId - ignored
  7286. JET_paramWaitLogFlush,
  7287. 0, //wait 0 msecs after commit
  7288. //before flushing
  7289. NULL //ignored
  7290. )
  7291. );
  7292. //
  7293. // There does not seem to be any need to set
  7294. // Log Flush Period.
  7295. //
  7296. }
  7297. //
  7298. // set the log file path
  7299. //
  7300. if (WinsCnf.pLogFilePath == NULL)
  7301. {
  7302. //
  7303. // We should use the same directory as
  7304. // the one for system.mdb file
  7305. //
  7306. WinsCnf.pLogFilePath = LOGFILE_PATH;
  7307. fFreeMem = FALSE;
  7308. }
  7309. DBGPRINT1(FLOW, "SetSystemParam: LogFilePath = (%s)\n", WinsCnf.pLogFilePath);
  7310. //
  7311. // Set the log file path.
  7312. //
  7313. CALL_M(JetSetSystemParameter(
  7314. &sJetInstance,
  7315. (JET_SESID)0, //SesId - ignored
  7316. JET_paramLogFilePath,
  7317. 0, //ignored
  7318. WinsCnf.pLogFilePath
  7319. //pLogFilePath
  7320. )
  7321. );
  7322. //
  7323. // Free this memory. It is not needed any more
  7324. //
  7325. if (fFreeMem)
  7326. {
  7327. WinsMscDealloc(WinsCnf.pLogFilePath);
  7328. }
  7329. }
  7330. else
  7331. {
  7332. if (!RtlEqualMemory(WinsCnf.pLogFilePath, LOGFILE_PATH, sizeof(LOGFILE_PATH)))
  7333. {
  7334. DBGPRINT0(DET, "SetSystemParam: Setting Log file path again\n");
  7335. WinsCnf.pLogFilePath = LOGFILE_PATH;
  7336. CALL_M(JetSetSystemParameter(
  7337. &sJetInstance,
  7338. (JET_SESID)0, //SesId - ignored
  7339. JET_paramLogFilePath,
  7340. 0, //ignored
  7341. WinsCnf.pLogFilePath
  7342. )
  7343. );
  7344. }
  7345. }
  7346. return WINS_SUCCESS;
  7347. }
  7348. STATUS
  7349. SetSystemParamsJet500(
  7350. BOOL fBeforeInit
  7351. )
  7352. /*++
  7353. Routine Description:
  7354. This function is called to set the system parameters for Jet
  7355. Arguments:
  7356. fBeforeInit - indicates whether this function has been called
  7357. prior to JetInit
  7358. Externals Used:
  7359. None
  7360. Return Value:
  7361. Success status codes --
  7362. Error status codes --
  7363. --*/
  7364. {
  7365. JET_ERR JetRetStat;
  7366. DBGENTER("SetSystemParam500\n");
  7367. if (fBeforeInit)
  7368. {
  7369. //
  7370. // Path for the checkpoint file jet.chk to be located
  7371. //
  7372. CALL_M(JetSetSystemParameter(
  7373. &sJetInstance,
  7374. (JET_SESID)0, //SesId - ignored
  7375. JET_paramSystemPath_OLD,
  7376. 0,
  7377. CHKPOINT_PATH
  7378. )
  7379. );
  7380. //
  7381. // Basename to use for jet*.log and jet.chk
  7382. //
  7383. CALL_M(JetSetSystemParameter(
  7384. &sJetInstance,
  7385. (JET_SESID)0, //SesId - ignored
  7386. JET_paramBaseName_OLD,
  7387. 0,
  7388. BASENAME
  7389. )
  7390. );
  7391. //
  7392. // Max size of the log file in kb.
  7393. //
  7394. CALL_M(JetSetSystemParameter(
  7395. &sJetInstance,
  7396. (JET_SESID)0, //SesId - ignored
  7397. JET_paramLogFileSize_OLD,
  7398. 1024, //set to one full meg (#96543)
  7399. NULL //ignored
  7400. )
  7401. );
  7402. CALL_M(JetSetSystemParameter(
  7403. &sJetInstance,
  7404. (JET_SESID)0, //SesId - ignored
  7405. JET_paramTempPath_OLD,
  7406. 0,
  7407. TEMP_DB_PATH //ignored
  7408. )
  7409. );
  7410. PERF("Check the following two things")
  7411. //
  7412. // We want some aggressive flushing. The performance impact
  7413. // is very trivial - Ian Jose 7/12/93
  7414. //
  7415. //
  7416. // The max number of buffers for database usage
  7417. //
  7418. // The default number is 500. 600 events are allocated
  7419. // for 500 buffers -- Ian 10/21/93. Each buffer is
  7420. // 4K. By keeping the number small, we impact performamce
  7421. //
  7422. CALL_M(JetSetSystemParameter(
  7423. &sJetInstance,
  7424. (JET_SESID)0, //SesId - ignored
  7425. JET_paramMaxBuffers_OLD,
  7426. WinsCnf.NoOfDbBuffers,//200,
  7427. NULL //ignored
  7428. )
  7429. );
  7430. //
  7431. // The max. number of buffers to store old version of a
  7432. // a record (snapshot at the start of a transaction)
  7433. // Each version store is 16k bytes. A version store
  7434. // stores structures that hold information derived from
  7435. // a snapshot of the database prior to an insert (20 bytes
  7436. // roughly) or update (size of the record + 20 bytes).
  7437. //
  7438. // For small transactions (i.e. a transaction around each
  7439. // update), this number should be >= the max. number of
  7440. // sessions that can be updating/inserting at the same time.
  7441. // Each session will have one version bucket. Since 16k of
  7442. // version bucket size can result in a lot of wastage per
  7443. // session (since each record is < .5k, and on the average
  7444. // around 50 bytes), it may be better to specify the
  7445. // max. size of the version bucket (<< 16k). Ian will
  7446. //provide a system param for this if we absolutely need it
  7447. //
  7448. // 3/4/93
  7449. //16kBytes should be enough for the transactions WINS does,
  7450. //but if all the sessions are in transactions at the same time
  7451. //and they all happen to have their small transactions traverse
  7452. //2 buckets then the peak requirement is 2 buckets per session.
  7453. //We could shorten the buckets to 8kBytes, or 4kBytes, and you
  7454. //could allocate 2 per session?
  7455. //
  7456. CALL_M(JetSetSystemParameter(
  7457. &sJetInstance,
  7458. (JET_SESID)0, //SesId - ignored
  7459. JET_paramMaxVerPages_OLD,
  7460. MAX_NO_SESSIONS * 6, //10-4-95 Bump it up more
  7461. //MAX_NO_SESSIONS * 2,
  7462. NULL //ignored
  7463. )
  7464. );
  7465. //
  7466. // Set the File Control Block Param
  7467. //
  7468. // This is the max. number of tables that can be open
  7469. // at any time. If multiple threads open the same table
  7470. // they use the same FCB. FCB is 1 per table/index.
  7471. // Now, for a create database, we need atleast 18 FCBS
  7472. // and 18 IDBS. However apart from create database and
  7473. // ddl operations, we don't need to have these tables open.
  7474. // Default value is 300. Size of an FCB is 112 bytes.
  7475. //
  7476. CALL_M(JetSetSystemParameter(
  7477. &sJetInstance,
  7478. (JET_SESID)0, //SesId - ignored
  7479. JET_paramMaxOpenTables_OLD,
  7480. 56, //18 + 10,
  7481. NULL //ignored
  7482. )
  7483. );
  7484. //
  7485. // Set the File Usage Control Block to 100.
  7486. // This parameter indicates the max. number of cursors
  7487. // that can be open at any one time. This is
  7488. // therefore dependent on the the max. number of sessions
  7489. // that we can have running concurrently. For each session,
  7490. // there would be 4 cursors (for the two tables) + a certain
  7491. // number of internal cursors. For good measure we add
  7492. // a pad. Default value is 300. Size of each is 200 bytes.
  7493. // We use MAX_SESSIONS * 4 + pad
  7494. // (around 100)
  7495. //
  7496. CALL_M(JetSetSystemParameter(
  7497. &sJetInstance,
  7498. (JET_SESID)0, //SesId - ignored
  7499. JET_paramMaxCursors_OLD,
  7500. (MAX_NO_SESSIONS * 8 /*4*/) + 32,
  7501. NULL //ignored
  7502. )
  7503. );
  7504. //
  7505. // Set the number of index description blocks
  7506. // This is one per table/index. We have two tables
  7507. // each with two indices. We use 9 (see comment for
  7508. // FCBs above). Default value is 300.
  7509. // Size of each is 128 bytes.
  7510. //
  7511. CALL_M(JetSetSystemParameter(
  7512. &sJetInstance,
  7513. (JET_SESID)0, //SesId - ignored
  7514. JET_paramMaxOpenTableIndexes_OLD,
  7515. 56, //18 + 10,
  7516. NULL //ignored
  7517. )
  7518. );
  7519. //
  7520. // Set the Sort Control block.
  7521. // This should be 1 per concurrent Create Index.
  7522. // Default value is 20. Size of each is 612 bytes.
  7523. // In the case of WINS, the main thread creates the
  7524. // indices. We should be setting it to 1. Let us
  7525. // however set it to 3.
  7526. //
  7527. CALL_M(JetSetSystemParameter(
  7528. &sJetInstance,
  7529. (JET_SESID)0, //SesId - ignored
  7530. JET_paramMaxTemporaryTables_OLD ,
  7531. 10, //1 + 2,
  7532. NULL //ignored
  7533. )
  7534. );
  7535. //
  7536. // Set the Number for the Database Attribute Blocks
  7537. //
  7538. // This is max. number of Open Databases done. Since we
  7539. // can have a max of MAX_NO_SESSIONS at one time. This should
  7540. // be equal to that number (since we have just one database)
  7541. // Default number is 100. Size is 14 bytes
  7542. //
  7543. // JET_paramMaxOpenDatabase is removed. Jonathan Liem (1/6/97)
  7544. CALL_M(JetSetSystemParameter(
  7545. &sJetInstance,
  7546. (JET_SESID)0, //SesId - ignored
  7547. JET_paramMaxOpenDatabases_OLD,
  7548. MAX_NO_SESSIONS * 4, //*2,
  7549. NULL //ignored
  7550. )
  7551. );
  7552. //
  7553. // The min percentage of buffers not yet dirtied before
  7554. // background flushing begins
  7555. //
  7556. CALL_M(JetSetSystemParameter(
  7557. &sJetInstance,
  7558. (JET_SESID)0, //SesId - ignored
  7559. JET_paramBfThrshldLowPrcnt_OLD,
  7560. 80,
  7561. NULL //ignored
  7562. )
  7563. );
  7564. //
  7565. // The max percentage of buffers not yet dirtied before
  7566. // background flushing begins
  7567. //
  7568. CALL_M(JetSetSystemParameter(
  7569. &sJetInstance,
  7570. (JET_SESID)0, //SesId - ignored
  7571. JET_paramBfThrshldHighPrcnt_OLD,
  7572. 100,
  7573. NULL //ignored
  7574. )
  7575. );
  7576. //
  7577. // The max. number of sessions that can be open at any time
  7578. //
  7579. // Note: Jet does not preallocate resources corresponding
  7580. // to the max. value. It allocates them dynamically upto
  7581. // the limit -- according to Ian Jose 7/12/93
  7582. //
  7583. // When checked with Ian again on 10/21, he said that they are
  7584. // allocated STATICally
  7585. //
  7586. CHECK("Make sure the comment above remains true")
  7587. FUTURES("Make sure the comment above remains true")
  7588. CALL_M(JetSetSystemParameter(
  7589. &sJetInstance,
  7590. (JET_SESID)0, //SesId - ignored
  7591. JET_paramMaxSessions_OLD,
  7592. MAX_NO_SESSIONS,
  7593. NULL //ignored
  7594. )
  7595. );
  7596. //
  7597. // Turn on logging if not prohibited by administrator
  7598. //
  7599. if (WinsCnf.fLoggingOn)
  7600. {
  7601. FUTURES("Internationalize the following when jet is internationalized")
  7602. //
  7603. // Turn logging (recovery) on
  7604. //
  7605. CALL_M(JetSetSystemParameter(
  7606. &sJetInstance,
  7607. (JET_SESID)0, //SesId - ignored
  7608. 30, // JET_paramRecovery not available,
  7609. 0, //ignored
  7610. "on"
  7611. )
  7612. );
  7613. //
  7614. // The number of log sectors. Each sector is
  7615. // 512 bytes. We should keep the size more than
  7616. // the threshold so that if the threshold is reached
  7617. // and flushing starts, Jet can still continue to
  7618. // log in the spare sectors. Point to note is that
  7619. // if the log rate is faster than the flush rate, then
  7620. // the Jet engine thread will not be able to log when
  7621. // the entire buffer is filled up. It will then wait
  7622. // until space becomes available.
  7623. //
  7624. CALL_M(JetSetSystemParameter(
  7625. &sJetInstance,
  7626. (JET_SESID)0, //SesId - ignored
  7627. JET_paramLogBuffers_OLD,
  7628. 30, //30 sectors
  7629. NULL //ignored
  7630. )
  7631. );
  7632. //
  7633. // Set the number of log buffers dirtied before they
  7634. // are flushed. This number should always be less than
  7635. // the number for LogBuffers so that spare sectors
  7636. // are there for concurrent logging. Also, we should
  7637. // make this number high enough to handle burst of
  7638. // traffic.
  7639. //
  7640. CALL_M(JetSetSystemParameter(
  7641. &sJetInstance,
  7642. (JET_SESID)0, //SesId - ignored
  7643. 18, //JET_paramLogFlushThreshold,
  7644. 20, //20 sectors dirtied causes
  7645. //flush
  7646. NULL //ignored
  7647. )
  7648. );
  7649. //
  7650. // Set the wait time (in msecs) to wait prior to
  7651. // flushing the log on commit transaction to allow
  7652. // other users (sessions) to share the flush
  7653. //
  7654. //
  7655. // This is the time after which the user (a session)
  7656. // will ask the log manager to flush. If we specify
  7657. // 0 here than it means flush every time a transaction
  7658. // commits. In the WINS server case, every insertion
  7659. // or modification is done under an implicit
  7660. // transaction. So, it means that there will be
  7661. // a flush after every such transaction. It has
  7662. // been seen on a 486/66 (Cheen Liao) machine that
  7663. // it takes roughly 16 msecs to do the flush. The
  7664. // time it takes to do the flush is dependent upon
  7665. // the type of disk (how fast it is), the CPU speed,
  7666. // the type of file system etc. We can for now
  7667. // go with the assumption that it is in the range
  7668. // 15-25 msecs. I am pushing for this WaitTime to
  7669. // be made a session specific param so that it can
  7670. // be changed on the fly if the admin. finds that
  7671. // the WINS server is slow due to the WaitTime being
  7672. // very low or if it finds it to be so large that
  7673. // in case of a crash, there is possibility to loose
  7674. // a lot of data.
  7675. //
  7676. // Making this session specific is also very important
  7677. // for replication where we do want to set it to
  7678. // a high value (high enough to ensure that most
  7679. // of the records that need to be inserted are
  7680. // inserted before a flush action takes place. The
  7681. // wait time would be set every time a bunch of
  7682. // records are pulled in for replication. It will
  7683. // be computed based on the number of records pulled
  7684. // in and the time it takes to insert one record in the
  7685. // jet buffer. The wait time should preferably be < than
  7686. // the above computed time (it does not have to be).
  7687. //
  7688. // NOTE: In the Pull thread, I will need to start
  7689. // two sessions, one for updating the OwnerId-Version
  7690. // number table (0 wait time) and the other to
  7691. // update the name-address mapping table (wait time
  7692. // computed based on the factors mentioned above)
  7693. //
  7694. // The following will set the WaitLogFlush time for
  7695. // all sessions.
  7696. //
  7697. CALL_M(JetSetSystemParameter(
  7698. &sJetInstance,
  7699. (JET_SESID)0, //SesId - ignored
  7700. JET_paramWaitLogFlush_OLD,
  7701. 0, //wait 0 msecs after commit
  7702. //before flushing
  7703. NULL //ignored
  7704. )
  7705. );
  7706. //
  7707. // There does not seem to be any need to set
  7708. // Log Flush Period.
  7709. //
  7710. //
  7711. // set the log file path
  7712. //
  7713. FUTURES("Use DEFAULT_LOG_PATH after putting it in a header file")
  7714. if (WinsCnf.pLogFilePath == NULL)
  7715. {
  7716. //
  7717. // We should use the same directory as
  7718. // the one for system.mdb file
  7719. //
  7720. // pLogFilePath = ".\\wins";
  7721. WinsCnf.pLogFilePath = LOGFILE_PATH;
  7722. }
  7723. else
  7724. {
  7725. #if 0
  7726. #ifdef UNICODE
  7727. CHAR AsciiLogFilePath[WINS_MAX_FILENAME_SZ];
  7728. WinsMscConvertUnicodeStringToAscii(
  7729. (LPBYTE)WinsCnf.pLogFilePath,
  7730. AsciiLogFilePath,
  7731. WINS_MAX_FILENAME_SZ
  7732. );
  7733. pLogFilePath = (LPBYTE)AsciiLogFilePath;
  7734. #else
  7735. pLogFilePath = (LPBYTE)WinsCnf.pLogFilePath;
  7736. #endif
  7737. #endif
  7738. }
  7739. DBGPRINT1(FLOW, "SetSystemParam: LogFilePath = (%s)\n", WinsCnf.pLogFilePath);
  7740. //
  7741. // Set the log file path.
  7742. //
  7743. CALL_M(JetSetSystemParameter(
  7744. &sJetInstance,
  7745. (JET_SESID)0, //SesId - ignored
  7746. JET_paramLogFilePath_OLD,
  7747. 0, //ignored
  7748. WinsCnf.pLogFilePath
  7749. //pLogFilePath
  7750. )
  7751. );
  7752. }
  7753. }
  7754. else
  7755. {
  7756. if (!RtlEqualMemory(WinsCnf.pLogFilePath, LOGFILE_PATH, sizeof(LOGFILE_PATH)))
  7757. {
  7758. DBGPRINT0(DET, "SetSystemParam: Setting Log file path again\n");
  7759. WinsCnf.pLogFilePath = LOGFILE_PATH;
  7760. CALL_M(JetSetSystemParameter(
  7761. &sJetInstance,
  7762. (JET_SESID)0, //SesId - ignored
  7763. JET_paramLogFilePath_OLD,
  7764. 0, //ignored
  7765. WinsCnf.pLogFilePath
  7766. )
  7767. );
  7768. }
  7769. }
  7770. return WINS_SUCCESS;
  7771. }
  7772. STATUS
  7773. SetSystemParamsJet200(
  7774. BOOL fBeforeInit
  7775. )
  7776. /*++
  7777. Routine Description:
  7778. This function is called to set the system parameters for Jet
  7779. Arguments:
  7780. fBeforeInit - indicates whether this function has been called
  7781. prior to JetInit
  7782. Externals Used:
  7783. None
  7784. Return Value:
  7785. Success status codes --
  7786. Error status codes --
  7787. --*/
  7788. {
  7789. JET_ERR JetRetStat;
  7790. BOOL fFreeMem = TRUE;
  7791. DBGENTER("SetSystemParam200\n");
  7792. if (fBeforeInit)
  7793. {
  7794. CALL_M(JetSetSystemParameter(
  7795. &sJetInstance,
  7796. (JET_SESID)0, //SesId - ignored
  7797. JET_paramSysDbPath_OLD,
  7798. 0,
  7799. SYS_DB_PATH //ignored
  7800. )
  7801. );
  7802. CALL_M(JetSetSystemParameter(
  7803. &sJetInstance,
  7804. (JET_SESID)0, //SesId - ignored
  7805. JET_paramTempPath_OLD,
  7806. 0,
  7807. TEMP_DB_PATH //ignored
  7808. )
  7809. );
  7810. PERF("Check the following two things")
  7811. //
  7812. // We want some aggressive flushing. The performance impact
  7813. // is very trivial - Ian Jose 7/12/93
  7814. //
  7815. //
  7816. // The max number of buffers for database usage
  7817. //
  7818. // The default number is 500. 600 events are allocated
  7819. // for 500 buffers -- Ian 10/21/93. Each buffer is
  7820. // 4K. By keeping the number small, we impact performamce
  7821. //
  7822. CALL_M(JetSetSystemParameter(
  7823. &sJetInstance,
  7824. (JET_SESID)0, //SesId - ignored
  7825. JET_paramMaxBuffers_OLD,
  7826. WinsCnf.NoOfDbBuffers,//200,
  7827. NULL //ignored
  7828. )
  7829. );
  7830. //
  7831. // The max. number of buffers to store old version of a
  7832. // a record (snapshot at the start of a transaction)
  7833. // Each version store is 16k bytes. A version store
  7834. // stores structures that hold information derived from
  7835. // a snapshot of the database prior to an insert (20 bytes
  7836. // roughly) or update (size of the record + 20 bytes).
  7837. //
  7838. // For small transactions (i.e. a transaction around each
  7839. // update), this number should be >= the max. number of
  7840. // sessions that can be updating/inserting at the same time.
  7841. // Each session will have one version bucket. Since 16k of
  7842. // version bucket size can result in a lot of wastage per
  7843. // session (since each record is < .5k, and on the average
  7844. // around 50 bytes), it may be better to specify the
  7845. // max. size of the version bucket (<< 16k). Ian will
  7846. //provide a system param for this if we absolutely need it
  7847. //
  7848. // 3/4/93
  7849. //16kBytes should be enough for the transactions WINS does,
  7850. //but if all the sessions are in transactions at the same time
  7851. //and they all happen to have their small transactions traverse
  7852. //2 buckets then the peak requirement is 2 buckets per session.
  7853. //We could shorten the buckets to 8kBytes, or 4kBytes, and you
  7854. //could allocate 2 per session?
  7855. //
  7856. CALL_M(JetSetSystemParameter(
  7857. &sJetInstance,
  7858. (JET_SESID)0, //SesId - ignored
  7859. JET_paramMaxVerPages_OLD,
  7860. MAX_NO_SESSIONS * 6, //10-4-95 Bump it up more
  7861. //MAX_NO_SESSIONS * 2,
  7862. NULL //ignored
  7863. )
  7864. );
  7865. //
  7866. // Set the File Control Block Param
  7867. //
  7868. // This is the max. number of tables that can be open
  7869. // at any time. If multiple threads open the same table
  7870. // they use the same FCB. FCB is 1 per table/index.
  7871. // Now, for a create database, we need atleast 18 FCBS
  7872. // and 18 IDBS. However apart from create database and
  7873. // ddl operations, we don't need to have these tables open.
  7874. // Default value is 300. Size of an FCB is 112 bytes.
  7875. //
  7876. CALL_M(JetSetSystemParameter(
  7877. &sJetInstance,
  7878. (JET_SESID)0, //SesId - ignored
  7879. JET_paramMaxOpenTables_OLD,
  7880. 56, //18 + 10,
  7881. NULL //ignored
  7882. )
  7883. );
  7884. //
  7885. // Set the File Usage Control Block to 100.
  7886. // This parameter indicates the max. number of cursors
  7887. // that can be open at any one time. This is
  7888. // therefore dependent on the the max. number of sessions
  7889. // that we can have running concurrently. For each session,
  7890. // there would be 4 cursors (for the two tables) + a certain
  7891. // number of internal cursors. For good measure we add
  7892. // a pad. Default value is 300. Size of each is 200 bytes.
  7893. // We use MAX_SESSIONS * 4 + pad
  7894. // (around 100)
  7895. //
  7896. CALL_M(JetSetSystemParameter(
  7897. &sJetInstance,
  7898. (JET_SESID)0, //SesId - ignored
  7899. JET_paramMaxCursors_OLD,
  7900. (MAX_NO_SESSIONS * 8 /*4*/) + 32,
  7901. NULL //ignored
  7902. )
  7903. );
  7904. //
  7905. // Set the number of index description blocks
  7906. // This is one per table/index. We have two tables
  7907. // each with two indices. We use 9 (see comment for
  7908. // FCBs above). Default value is 300.
  7909. // Size of each is 128 bytes.
  7910. //
  7911. CALL_M(JetSetSystemParameter(
  7912. &sJetInstance,
  7913. (JET_SESID)0, //SesId - ignored
  7914. JET_paramMaxOpenTableIndexes_OLD,
  7915. 56, //18 + 10,
  7916. NULL //ignored
  7917. )
  7918. );
  7919. //
  7920. // Set the Sort Control block.
  7921. // This should be 1 per concurrent Create Index.
  7922. // Default value is 20. Size of each is 612 bytes.
  7923. // In the case of WINS, the main thread creates the
  7924. // indices. We should be setting it to 1. Let us
  7925. // however set it to 3.
  7926. //
  7927. CALL_M(JetSetSystemParameter(
  7928. &sJetInstance,
  7929. (JET_SESID)0, //SesId - ignored
  7930. JET_paramMaxTemporaryTables_OLD ,
  7931. 10, //1 + 2,
  7932. NULL //ignored
  7933. )
  7934. );
  7935. //
  7936. // Set the Number for the Database Attribute Blocks
  7937. //
  7938. // This is max. number of Open Databases done. Since we
  7939. // can have a max of MAX_NO_SESSIONS at one time. This should
  7940. // be equal to that number (since we have just one database)
  7941. // Default number is 100. Size is 14 bytes
  7942. //
  7943. // JET_paramMaxOpenDatabase is removed. Jonathan Liem (1/6/97)
  7944. CALL_M(JetSetSystemParameter(
  7945. &sJetInstance,
  7946. (JET_SESID)0, //SesId - ignored
  7947. JET_paramMaxOpenDatabases_OLD,
  7948. MAX_NO_SESSIONS * 4, //*2,
  7949. NULL //ignored
  7950. )
  7951. );
  7952. //
  7953. // The min percentage of buffers not yet dirtied before
  7954. // background flushing begins
  7955. //
  7956. CALL_M(JetSetSystemParameter(
  7957. &sJetInstance,
  7958. (JET_SESID)0, //SesId - ignored
  7959. JET_paramBfThrshldLowPrcnt_OLD,
  7960. 80,
  7961. NULL //ignored
  7962. )
  7963. );
  7964. //
  7965. // The max percentage of buffers not yet dirtied before
  7966. // background flushing begins
  7967. //
  7968. CALL_M(JetSetSystemParameter(
  7969. &sJetInstance,
  7970. (JET_SESID)0, //SesId - ignored
  7971. JET_paramBfThrshldHighPrcnt_OLD,
  7972. 100,
  7973. NULL //ignored
  7974. )
  7975. );
  7976. //
  7977. // The max. number of sessions that can be open at any time
  7978. //
  7979. // Note: Jet does not preallocate resources corresponding
  7980. // to the max. value. It allocates them dynamically upto
  7981. // the limit -- according to Ian Jose 7/12/93
  7982. //
  7983. // When checked with Ian again on 10/21, he said that they are
  7984. // allocated STATICally
  7985. //
  7986. CHECK("Make sure the comment above remains true")
  7987. FUTURES("Make sure the comment above remains true")
  7988. CALL_M(JetSetSystemParameter(
  7989. &sJetInstance,
  7990. (JET_SESID)0, //SesId - ignored
  7991. JET_paramMaxSessions_OLD,
  7992. MAX_NO_SESSIONS,
  7993. NULL //ignored
  7994. )
  7995. );
  7996. //
  7997. // Turn on logging if not prohibited by administrator
  7998. //
  7999. if (WinsCnf.fLoggingOn)
  8000. {
  8001. FUTURES("Internationalize the following when jet is internationalized")
  8002. //
  8003. // Turn logging (recovery) on
  8004. //
  8005. CALL_M(JetSetSystemParameter(
  8006. &sJetInstance,
  8007. (JET_SESID)0, //SesId - ignored
  8008. 30, // JET_paramRecovery_OLD not available,
  8009. 0, //ignored
  8010. "on"
  8011. )
  8012. );
  8013. //
  8014. // The number of log sectors. Each sector is
  8015. // 512 bytes. We should keep the size more than
  8016. // the threshold so that if the threshold is reached
  8017. // and flushing starts, Jet can still continue to
  8018. // log in the spare sectors. Point to note is that
  8019. // if the log rate is faster than the flush rate, then
  8020. // the Jet engine thread will not be able to log when
  8021. // the entire buffer is filled up. It will then wait
  8022. // until space becomes available.
  8023. //
  8024. CALL_M(JetSetSystemParameter(
  8025. &sJetInstance,
  8026. (JET_SESID)0, //SesId - ignored
  8027. JET_paramLogBuffers_OLD,
  8028. 30, //30 sectors
  8029. NULL //ignored
  8030. )
  8031. );
  8032. //
  8033. // Set the number of log buffers dirtied before they
  8034. // are flushed. This number should always be less than
  8035. // the number for LogBuffers so that spare sectors
  8036. // are there for concurrent logging. Also, we should
  8037. // make this number high enough to handle burst of
  8038. // traffic.
  8039. //
  8040. CALL_M(JetSetSystemParameter(
  8041. &sJetInstance,
  8042. (JET_SESID)0, //SesId - ignored
  8043. 18, // JET_paramLogFlushThreshold,
  8044. 20, //20 sectors dirtied causes
  8045. //flush
  8046. NULL //ignored
  8047. )
  8048. );
  8049. //
  8050. // Set the wait time (in msecs) to wait prior to
  8051. // flushing the log on commit transaction to allow
  8052. // other users (sessions) to share the flush
  8053. //
  8054. //
  8055. // This is the time after which the user (a session)
  8056. // will ask the log manager to flush. If we specify
  8057. // 0 here than it means flush every time a transaction
  8058. // commits. In the WINS server case, every insertion
  8059. // or modification is done under an implicit
  8060. // transaction. So, it means that there will be
  8061. // a flush after every such transaction. It has
  8062. // been seen on a 486/66 (Cheen Liao) machine that
  8063. // it takes roughly 16 msecs to do the flush. The
  8064. // time it takes to do the flush is dependent upon
  8065. // the type of disk (how fast it is), the CPU speed,
  8066. // the type of file system etc. We can for now
  8067. // go with the assumption that it is in the range
  8068. // 15-25 msecs. I am pushing for this WaitTime to
  8069. // be made a session specific param so that it can
  8070. // be changed on the fly if the admin. finds that
  8071. // the WINS server is slow due to the WaitTime being
  8072. // very low or if it finds it to be so large that
  8073. // in case of a crash, there is possibility to loose
  8074. // a lot of data.
  8075. //
  8076. // Making this session specific is also very important
  8077. // for replication where we do want to set it to
  8078. // a high value (high enough to ensure that most
  8079. // of the records that need to be inserted are
  8080. // inserted before a flush action takes place. The
  8081. // wait time would be set every time a bunch of
  8082. // records are pulled in for replication. It will
  8083. // be computed based on the number of records pulled
  8084. // in and the time it takes to insert one record in the
  8085. // jet buffer. The wait time should preferably be < than
  8086. // the above computed time (it does not have to be).
  8087. //
  8088. // NOTE: In the Pull thread, I will need to start
  8089. // two sessions, one for updating the OwnerId-Version
  8090. // number table (0 wait time) and the other to
  8091. // update the name-address mapping table (wait time
  8092. // computed based on the factors mentioned above)
  8093. //
  8094. // The following will set the WaitLogFlush time for
  8095. // all sessions.
  8096. //
  8097. CALL_M(JetSetSystemParameter(
  8098. &sJetInstance,
  8099. (JET_SESID)0, //SesId - ignored
  8100. JET_paramWaitLogFlush_OLD,
  8101. 0, //wait 0 msecs after commit
  8102. //before flushing
  8103. NULL //ignored
  8104. )
  8105. );
  8106. //
  8107. // There does not seem to be any need to set
  8108. // Log Flush Period.
  8109. //
  8110. //
  8111. // set the log file path
  8112. //
  8113. FUTURES("Use DEFAULT_LOG_PATH after putting it in a header file")
  8114. if (WinsCnf.pLogFilePath == NULL)
  8115. {
  8116. //
  8117. // We should use the same directory as
  8118. // the one for system.mdb file
  8119. //
  8120. // pLogFilePath = ".\\wins";
  8121. WinsCnf.pLogFilePath = LOGFILE_PATH;
  8122. fFreeMem = FALSE;
  8123. }
  8124. else
  8125. {
  8126. #if 0
  8127. #ifdef UNICODE
  8128. CHAR AsciiLogFilePath[WINS_MAX_FILENAME_SZ];
  8129. WinsMscConvertUnicodeStringToAscii(
  8130. (LPBYTE)WinsCnf.pLogFilePath,
  8131. AsciiLogFilePath,
  8132. WINS_MAX_FILENAME_SZ
  8133. );
  8134. pLogFilePath = (LPBYTE)AsciiLogFilePath;
  8135. #else
  8136. pLogFilePath = (LPBYTE)WinsCnf.pLogFilePath;
  8137. #endif
  8138. #endif
  8139. }
  8140. DBGPRINT1(FLOW, "SetSystemParam: LogFilePath = (%s)\n", WinsCnf.pLogFilePath);
  8141. //
  8142. // Set the log file path.
  8143. //
  8144. CALL_M(JetSetSystemParameter(
  8145. &sJetInstance,
  8146. (JET_SESID)0, //SesId - ignored
  8147. JET_paramLogFilePath_OLD,
  8148. 0, //ignored
  8149. WinsCnf.pLogFilePath
  8150. //pLogFilePath
  8151. )
  8152. );
  8153. //
  8154. // Free this memory. It is not needed any more
  8155. //
  8156. if (fFreeMem)
  8157. {
  8158. WinsMscDealloc(WinsCnf.pLogFilePath);
  8159. }
  8160. }
  8161. }
  8162. else
  8163. {
  8164. if (!RtlEqualMemory(WinsCnf.pLogFilePath, LOGFILE_PATH, sizeof(LOGFILE_PATH)))
  8165. {
  8166. DBGPRINT0(DET, "SetSystemParam: Setting Log file path again\n");
  8167. WinsCnf.pLogFilePath = LOGFILE_PATH;
  8168. CALL_M(JetSetSystemParameter(
  8169. &sJetInstance,
  8170. (JET_SESID)0, //SesId - ignored
  8171. JET_paramLogFilePath_OLD,
  8172. 0, //ignored
  8173. WinsCnf.pLogFilePath
  8174. )
  8175. );
  8176. }
  8177. }
  8178. return WINS_SUCCESS;
  8179. }
  8180. STATUS
  8181. SetSystemParams(
  8182. BOOL fBeforeInit
  8183. )
  8184. /*++
  8185. Routine Description:
  8186. This function is called to set the system parameters for Jet
  8187. Arguments:
  8188. fBeforeInit - indicates whether this function has been called
  8189. prior to JetInit
  8190. Externals Used:
  8191. None
  8192. Return Value:
  8193. Success status codes --
  8194. Error status codes --
  8195. Error Handling:
  8196. Called by:
  8197. Side Effects:
  8198. Comments:
  8199. None
  8200. --*/
  8201. {
  8202. if (DynLoadJetVersion >= DYN_LOAD_JET_600) {
  8203. return SetSystemParamsJet600( fBeforeInit );
  8204. }
  8205. else if (DynLoadJetVersion == DYN_LOAD_JET_500)
  8206. {
  8207. return SetSystemParamsJet500( fBeforeInit );
  8208. } else {
  8209. return SetSystemParamsJet200( fBeforeInit );
  8210. }
  8211. }
  8212. VOID
  8213. UpdHighestVersNoRecIfReqd(
  8214. PWINSTHD_TLS_T pTls,
  8215. PNMSDB_ROW_INFO_T pRowInfo,
  8216. PNMSDB_STAT_INFO_T pStatInfo
  8217. )
  8218. /*++
  8219. Routine Description:
  8220. This function is called to check if the record being replaced is
  8221. the highest version number record owned by the local WINS. If so,
  8222. the special record that records the highest version number reached
  8223. for local records is updated to reflect the version number of the
  8224. record to be replaced
  8225. Arguments:
  8226. pTls - ptr to thread local storage,
  8227. pRowInfo - ptr to info of record to store in db
  8228. pStatInfo - ptr to info of record to replace in db
  8229. Externals Used:
  8230. None
  8231. Return Value:
  8232. NONE
  8233. Error Handling:
  8234. Called by:
  8235. NmsDbUpdateRow, NmsDbSeekNUpdate
  8236. Side Effects:
  8237. Comments:
  8238. This function is always called from inside the NmsNmhNamRegCrtSec
  8239. --*/
  8240. {
  8241. VERS_NO_T MyMaxVersNo;
  8242. //
  8243. // Decrement the value of the vers. no. counter by 1
  8244. //
  8245. NMSNMH_DEC_VERS_NO_M(NmsNmhMyMaxVersNo,
  8246. MyMaxVersNo
  8247. );
  8248. //
  8249. // If a local record is being replaced by a replica, then only are we
  8250. // interested in updating the special record
  8251. //
  8252. if ((pStatInfo->OwnerId == NMSDB_LOCAL_OWNER_ID) && (pRowInfo->OwnerId
  8253. != NMSDB_LOCAL_OWNER_ID))
  8254. {
  8255. //
  8256. // Check if the local record to be replaced has the highest
  8257. // version number that we know of for local records
  8258. //
  8259. if (LiEql(pStatInfo->VersNo, MyMaxVersNo))
  8260. {
  8261. //
  8262. // Update (or insert) the special record that records
  8263. // the highest version number reached
  8264. //
  8265. NmsDbUpdHighestVersNoRec(pTls, MyMaxVersNo, FALSE);
  8266. }
  8267. }
  8268. return;
  8269. }
  8270. STATUS
  8271. NmsDbUpdHighestVersNoRec(
  8272. IN PWINSTHD_TLS_T pTls,
  8273. IN VERS_NO_T MyMaxVersNo,
  8274. IN BOOL fEnterCrtSec
  8275. )
  8276. /*++
  8277. Routine Description:
  8278. This function is called to update the record that stores the
  8279. highest version number reached for entries owned by the local WINS.
  8280. Arguments:
  8281. pTls - Thread local storage
  8282. Externals Used:
  8283. None
  8284. Return Value:
  8285. NONE
  8286. Error Handling:
  8287. Called by:
  8288. NmsDbDoScavenging, UpdHighestVersNoRecIfReqd() in nmsdb.c
  8289. Side Effects:
  8290. Comments:
  8291. None
  8292. --*/
  8293. {
  8294. DWORD OwnerId = OWNER_ID_OF_SPEC_REC;
  8295. DWORD FldNo = 0;
  8296. JET_ERR JetRetStat;
  8297. DWORD ActFldLen = 0; //length of fld retrieved
  8298. JET_TABLEID TblId;
  8299. JET_SESID SesId;
  8300. DWORD FlagVal = 0;
  8301. COMM_ADD_T Add;
  8302. DBGENTER("NmsDbUpdHighestVersNoRec\n");
  8303. //
  8304. // pTls should be non NULL if this function was called by
  8305. // UpdHighestVersNoRecIfReqd()
  8306. //
  8307. if (pTls == NULL)
  8308. {
  8309. GET_TLS_M(pTls);
  8310. ASSERT(pTls != NULL);
  8311. }
  8312. TblId = pTls->NamAddTblId;
  8313. SesId = pTls->SesId;
  8314. /*
  8315. * Set the clustered index as the current index
  8316. */
  8317. CALL_M(
  8318. JetSetCurrentIndex( SesId,
  8319. TblId,
  8320. NMSDB_NAM_ADD_CLUST_INDEX_NAME
  8321. )
  8322. );
  8323. //
  8324. //
  8325. //if called by UpdHighestVersNoRecIfReqd(), fEnterCrtSec should be
  8326. // FALSE
  8327. //
  8328. if (fEnterCrtSec)
  8329. {
  8330. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  8331. }
  8332. try {
  8333. //
  8334. // If the special record exists in the db, seek to it
  8335. //
  8336. if (sfHighestVersNoRecExists)
  8337. {
  8338. DBGPRINT2(DET, "NmsDbUpdHighestVersNoRec: REPLACING SPECIAL OWNER ID RECORD. New Version # = (%d %d)\n", MyMaxVersNo.HighPart, MyMaxVersNo.LowPart);
  8339. //
  8340. // If the special record's version number is less than the
  8341. // version number passed to us, replace it with the new one
  8342. //
  8343. if (
  8344. (fEnterCrtSec == FALSE) ||
  8345. (LiGtr(MyMaxVersNo, sHighestVersNoSaved))
  8346. )
  8347. {
  8348. CALL_M( JetMakeKey(
  8349. SesId,
  8350. TblId,
  8351. spHighestVersNoRecName,
  8352. sizeof(spHighestVersNoRecName),
  8353. JET_bitNewKey
  8354. )
  8355. );
  8356. CALL_M(JetSeek(
  8357. SesId,
  8358. TblId,
  8359. JET_bitSeekEQ
  8360. )
  8361. );
  8362. CALL_M(JetBeginTransaction(SesId));
  8363. try{
  8364. JetRetStat = JetPrepareUpdate(
  8365. SesId,
  8366. TblId,
  8367. JET_prepReplace
  8368. );
  8369. if (
  8370. (JetRetStat != JET_errSuccess)
  8371. &&
  8372. (JetRetStat != JET_wrnNoWriteLock)
  8373. )
  8374. {
  8375. RET_M(JetRetStat);
  8376. }
  8377. //
  8378. // Update the version number
  8379. //
  8380. // add 5th column (this is the version number long(DWORD)
  8381. CALL_M( JetSetColumn(
  8382. SesId,
  8383. TblId,
  8384. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  8385. &MyMaxVersNo,
  8386. sizeof(VERS_NO_T),
  8387. 0,
  8388. NULL /*optional info */
  8389. )
  8390. );
  8391. //
  8392. // Update the record
  8393. //
  8394. CALL_M(JetUpdate (
  8395. SesId,
  8396. TblId,
  8397. NULL,
  8398. 0L,
  8399. NULL
  8400. )
  8401. );
  8402. }
  8403. finally {
  8404. if (AbnormalTermination())
  8405. {
  8406. // if there is an abnormal termination, we already have an error
  8407. // code here. We shouldn't override it with any other error code.
  8408. JetRollback(SesId, JET_bitRollbackAll);
  8409. }
  8410. else
  8411. {
  8412. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  8413. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  8414. CALL_M(JetCommitTransaction(SesId, JET_bitCommitFlush));
  8415. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  8416. sHighestVersNoSaved = MyMaxVersNo;
  8417. }
  8418. }
  8419. }
  8420. #ifdef WINSDBG
  8421. else
  8422. {
  8423. DBGPRINT0(DET, "NmsDbUpdHighestVersNoRec: The record has a higher version number the one we wish to store. NO UPDATE IS BEING MADE\n");
  8424. }
  8425. #endif
  8426. }
  8427. else // special record not there
  8428. {
  8429. DWORD TimeStamp = MAXLONG;
  8430. DBGPRINT2(DET, "NmsDbUpdHighestVersNoRec: INSERTING SPECIAL OWNER ID RECORD. Version # = (%d %d)\n", MyMaxVersNo.HighPart, MyMaxVersNo.LowPart);
  8431. CALL_M(JetBeginTransaction(SesId));
  8432. try {
  8433. JetRetStat = JetPrepareUpdate(
  8434. SesId,
  8435. TblId,
  8436. JET_prepInsert
  8437. );
  8438. if (
  8439. (JetRetStat != JET_errSuccess)
  8440. &&
  8441. (JetRetStat != JET_wrnNoWriteLock)
  8442. )
  8443. {
  8444. RET_M(JetRetStat);
  8445. }
  8446. //
  8447. // Set the name
  8448. //
  8449. CALL_M( JetSetColumn(
  8450. SesId,
  8451. TblId,
  8452. sNamAddTblRow[NAM_ADD_NAME_INDEX].Fid,
  8453. spHighestVersNoRecName,
  8454. sizeof(spHighestVersNoRecName),
  8455. 0,
  8456. NULL /*optional info */
  8457. )
  8458. );
  8459. /* Set the owner byte */
  8460. CALL_M( JetSetColumn(
  8461. SesId,
  8462. TblId,
  8463. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  8464. &OwnerId,
  8465. NAM_ADD_OWNERID_SIZE,
  8466. 0,
  8467. NULL /*optional info */
  8468. )
  8469. );
  8470. //
  8471. // Set the version number
  8472. //
  8473. // add 5th column (this is the version number long(DWORD)
  8474. CALL_M( JetSetColumn(
  8475. SesId,
  8476. TblId,
  8477. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  8478. &MyMaxVersNo,
  8479. sizeof(VERS_NO_T),
  8480. 0,
  8481. NULL /*optional info */
  8482. )
  8483. );
  8484. //
  8485. // Set the flags column. We mark it STATIC so that
  8486. // the scavenger thread does not pick it up for // scavenging. Even if that were not the case, we still need
  8487. // to set this column to avoid a JET_wrnColumnNull from
  8488. // JetRetrieveColumn (in NmsDbGetDataRecs).
  8489. //
  8490. NMSDB_SET_STATIC_M(FlagVal);
  8491. NMSDB_SET_STATE_M(FlagVal, NMSDB_E_ACTIVE);
  8492. CALL_M( JetSetColumn(
  8493. SesId,
  8494. TblId,
  8495. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  8496. &FlagVal,
  8497. sizeof(FlagVal),
  8498. 0,
  8499. NULL /*optional info */
  8500. )
  8501. );
  8502. //
  8503. // set the timestamp column to avoid getting a
  8504. // JET_wrnColumnNull from
  8505. // JetRetrieveColumn (in NmsDbGetDataRecsByName).
  8506. //
  8507. CALL_M( JetSetColumn(
  8508. SesId,
  8509. TblId,
  8510. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  8511. &TimeStamp,
  8512. sizeof(DWORD), /*change type to TIME_STAMP_T
  8513. *later*/
  8514. 0,
  8515. NULL /*optional info */
  8516. )
  8517. );
  8518. //
  8519. // set this address column to avoid a JET_wrnColumnNull from
  8520. // JetRetrieveColumn (in NmsDbGetDataRecsByName).
  8521. //
  8522. CALL_M( JetSetColumn(
  8523. SesId,
  8524. TblId,
  8525. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  8526. &Add,
  8527. sizeof(Add),
  8528. 0,
  8529. NULL /*optional info */
  8530. )
  8531. );
  8532. //
  8533. // Update the record
  8534. //
  8535. JetRetStat = JetUpdate (
  8536. SesId,
  8537. TblId,
  8538. NULL,
  8539. 0L,
  8540. NULL
  8541. );
  8542. } // end of try block
  8543. finally {
  8544. if (AbnormalTermination())
  8545. {
  8546. // if there is an abnormal termination, we already have an error
  8547. // code here. We shouldn't override it with any other error code.
  8548. JetRollback(SesId, JET_bitRollbackAll);
  8549. }
  8550. else
  8551. {
  8552. if (JetRetStat == JET_errSuccess)
  8553. {
  8554. #pragma prefast(suppress:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  8555. CALL_M(JetCommitTransaction(SesId, JET_bitCommitFlush));
  8556. }
  8557. else
  8558. {
  8559. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  8560. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  8561. CALL_M(JetRollback(SesId, JET_bitRollbackAll));
  8562. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  8563. }
  8564. //
  8565. // The only time we will get KeyDuplicate is if somebody
  8566. // entered the special name in the db. In such a
  8567. // situation, we should mark the record as existent
  8568. // such that next time we end up replacing the
  8569. // offensive record. Replacing this record can be
  8570. // done right now but at this stage it is not worth
  8571. // the time required to test it. In any case, the
  8572. // probability of problems due to this are miniscule.
  8573. //
  8574. if ( (JetRetStat == JET_errSuccess) ||
  8575. (JetRetStat == JET_errKeyDuplicate))
  8576. {
  8577. #ifdef WINSDBG
  8578. if (JetRetStat == JET_errKeyDuplicate)
  8579. {
  8580. DBGPRINT0(ERR, "NmsDbUpdHighestVersNoRec: DUPLICATE SPECIAL OWNER ID RECORD\n");
  8581. }
  8582. #endif
  8583. sHighestVersNoSaved = MyMaxVersNo;
  8584. sfHighestVersNoRecExists = TRUE;
  8585. }
  8586. }
  8587. }
  8588. }
  8589. } // end of try { .. }
  8590. finally {
  8591. if (fEnterCrtSec)
  8592. {
  8593. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  8594. }
  8595. }
  8596. DBGLEAVE("NmsDbUpdHighestVersNoRec\n");
  8597. return(WINS_SUCCESS);
  8598. }
  8599. STATUS
  8600. NmsDbDelDataRecs(
  8601. DWORD dwOwnerId,
  8602. VERS_NO_T MinVersNo,
  8603. VERS_NO_T MaxVersNo,
  8604. BOOL fEnterCrtSec,
  8605. BOOL fFragmentedDel
  8606. )
  8607. /*++
  8608. Routine Description:
  8609. This function is called to delete a specified range of records
  8610. of a WINS from the local db
  8611. Arguments:
  8612. pWinsAdd - Address of owner WINS
  8613. MinVersNo - Min. Vers. No
  8614. MaxVersNo = Max. Vers. No
  8615. Externals Used:
  8616. None
  8617. Return Value:
  8618. Success status codes -- WINS_SUCCESS
  8619. Error status codes -- WINS_FAILURE
  8620. Error Handling:
  8621. Called by:
  8622. WinsDelDbRecs
  8623. Side Effects:
  8624. Comments:
  8625. This function is called in the Pull thread or an RPC thread.
  8626. On exit, it sets the index to the clustered index on the
  8627. name-address table
  8628. --*/
  8629. {
  8630. JET_ERR JetRetStat;
  8631. DWORD ActFldLen; //length of fld retrieved
  8632. JET_TABLEID TblId;
  8633. JET_SESID SesId;
  8634. PWINSTHD_TLS_T pTls;
  8635. VERS_NO_T VersNo;
  8636. #if NEW_OWID
  8637. DWORD RecordOwnerId;
  8638. #else
  8639. DWORD RecordOwnerId = 0;
  8640. #endif
  8641. DWORD NoOfRecsUpd = 0;
  8642. STATUS RetStat = WINS_SUCCESS;
  8643. BOOL fAllToBeDeleted = FALSE;
  8644. //BOOL fTransActive = FALSE;
  8645. BOOL fEntered = FALSE;
  8646. DWORD Count = 0;
  8647. LONG RetVal;
  8648. DBGENTER("NmsDbDelDataRecs\n");
  8649. GET_TLS_M(pTls);
  8650. ASSERT(pTls != NULL);
  8651. TblId = pTls->NamAddTblId;
  8652. SesId = pTls->SesId;
  8653. if (fEnterCrtSec)
  8654. {
  8655. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  8656. fEntered = TRUE;
  8657. }
  8658. if (dwOwnerId == NMSDB_LOCAL_OWNER_ID)
  8659. {
  8660. NMSNMH_DEC_VERS_NO_M(NmsNmhMyMaxVersNo, VersNo);
  8661. }
  8662. else
  8663. {
  8664. if (WinsCnf.State_e != WINSCNF_E_INITING)
  8665. {
  8666. EnterCriticalSection(&RplVersNoStoreCrtSec);
  8667. VersNo = (pRplPullOwnerVersNo+dwOwnerId)->VersNo;
  8668. LeaveCriticalSection(&RplVersNoStoreCrtSec);
  8669. }
  8670. else
  8671. {
  8672. VersNo = (pRplPullOwnerVersNo+dwOwnerId)->VersNo;
  8673. }
  8674. }
  8675. //
  8676. // If both minimum and maximum version numbers specified are 0,
  8677. // it means all the records of the WINS need to be deleted
  8678. //
  8679. if (LiEqlZero(MinVersNo) && LiEqlZero(MaxVersNo))
  8680. {
  8681. fAllToBeDeleted = TRUE;
  8682. }
  8683. #if 0
  8684. else
  8685. {
  8686. if (LiGtr(MinVersNo, VersNo))
  8687. {
  8688. DBGPRINT4(DET, "NmsDbDelDataRecs: Wrong range to delete. Min. Vers. no (%d %d) is > the max. (%d %d) that this WINS server knows of.\n",
  8689. MinVersNo.HighPart, MinVersNo.LowPart,
  8690. VersNo.HighPart, VersNo.LowPart,
  8691. );
  8692. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  8693. return(WINS_FAILURE);
  8694. }
  8695. //
  8696. // We should never attempt to delete a record that is not in
  8697. // our database currently
  8698. //
  8699. MaxVersNo = LiGtr(MaxVersNo, VersNo) ? VersNo : MaxVersNo;
  8700. }
  8701. #endif
  8702. try {
  8703. //
  8704. // Let us make sure that the special record points to the highest
  8705. // version number that we know of for local records. Note:
  8706. // When there is atleast one record of a higher version number
  8707. // than the highest version numbered record to be deleted,
  8708. // there is no need to update the special record. Checking
  8709. // whether this is the case would be more overhead (in general).
  8710. //We therefore use the strategem of always updating the special record.
  8711. //
  8712. if (dwOwnerId == NMSDB_LOCAL_OWNER_ID)
  8713. {
  8714. NmsDbUpdHighestVersNoRec(pTls, VersNo, FALSE);
  8715. }
  8716. //
  8717. // Don't start a transaction since if the number of records are
  8718. // huge, the transaction can become long in duration and JetDelete
  8719. // may return an "out of Memory" error.
  8720. //
  8721. // Ian's comments on 8/26/94
  8722. //
  8723. // If you call JetDelete outside of any transaction, then JET
  8724. // internally wraps a begin transction/commit trnasaction around the
  8725. // delete. Another user at transaction level 0 will immediately see
  8726. // this change, but another user in a transction, i.e. at transaction
  8727. // level 1 or greater, will not see this change until they return to
  8728. // transaction level 0.
  8729. //
  8730. // Thus, you do not have to delete records in a transaction, unless
  8731. // you are deleting multiple records which must be deleted atomically,
  8732. // or which must be seen to be deleted atomically.
  8733. //
  8734. //CALL_M(JetBeginTransaction(SesId));
  8735. //fTransActive = TRUE;
  8736. do {
  8737. if (fFragmentedDel && fEnterCrtSec && !fEntered)
  8738. {
  8739. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  8740. fEntered = TRUE;
  8741. }
  8742. CALL_M( JetSetCurrentIndex(
  8743. pTls->SesId,
  8744. pTls->NamAddTblId,
  8745. NMSDB_NAM_ADD_PRIM_INDEX_NAME
  8746. )
  8747. );
  8748. CALL_M( JetMakeKey(
  8749. SesId,
  8750. TblId,
  8751. &dwOwnerId,
  8752. NAM_ADD_OWNERID_SIZE,
  8753. JET_bitNewKey //since this is the first
  8754. //data value of the key
  8755. )
  8756. );
  8757. CALL_M( JetMakeKey(
  8758. SesId,
  8759. TblId,
  8760. &MinVersNo,
  8761. sizeof(VERS_NO_T),
  8762. 0 //0 for grbit since this is not the
  8763. //first component of the key
  8764. )
  8765. );
  8766. JetRetStat = JetSeek(
  8767. SesId,
  8768. TblId,
  8769. JET_bitSeekGE
  8770. );
  8771. if (JetRetStat != JET_errRecordNotFound)
  8772. {
  8773. do {
  8774. CALL_M(JetRetrieveColumn(
  8775. SesId,
  8776. TblId,
  8777. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  8778. &RecordOwnerId,
  8779. NAM_ADD_OWNERID_SIZE,
  8780. &ActFldLen,
  8781. 0,
  8782. NULL
  8783. )
  8784. );
  8785. //
  8786. // if only tombstones are required, it means that we need
  8787. // all tombstones irrespective of owner
  8788. //
  8789. if (RecordOwnerId != dwOwnerId )
  8790. {
  8791. //
  8792. // We have exhausted all records for the owner. Break out
  8793. // of the loop
  8794. //
  8795. RetVal = -1; //to break out of the out loop
  8796. break;
  8797. }
  8798. //
  8799. // Retrieve the version number
  8800. //
  8801. CALL_M( JetRetrieveColumn(
  8802. SesId,
  8803. TblId,
  8804. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  8805. &VersNo,
  8806. sizeof(VERS_NO_T),
  8807. &ActFldLen,
  8808. 0,
  8809. NULL
  8810. )
  8811. );
  8812. //
  8813. // If MaxVersNo is not zero and VersNo retrieved is
  8814. // greater than it, break out of the loop.
  8815. //
  8816. // NOTE: fAllToBeDeleted is used instead of LiEqlZero()
  8817. // since the latter is a function call and would be
  8818. // costlier (this is the reason, why fAllToBeDeleted exists)
  8819. //
  8820. if (!fAllToBeDeleted && LiGtr(VersNo, MaxVersNo))
  8821. {
  8822. //
  8823. // We have acquired records upto MaxVersNo. Break out
  8824. // of the loop
  8825. //
  8826. RetVal = -1; // to break out of the outer loop
  8827. break;
  8828. }
  8829. CALL_M(JetDelete(
  8830. SesId,
  8831. TblId
  8832. )
  8833. );
  8834. #ifdef WINSDBG
  8835. NmsDbDelDelDataRecs++;
  8836. #endif
  8837. NoOfRecsUpd++;
  8838. } while(
  8839. ((RetVal = JetMove(SesId, TblId, JET_MoveNext, 0)) >= 0)
  8840. &&
  8841. (++Count < 50)
  8842. );
  8843. if (fFragmentedDel && fEntered)
  8844. {
  8845. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  8846. fEntered = FALSE;
  8847. MinVersNo = VersNo;
  8848. Count = 0;
  8849. }
  8850. if (RetVal < 0)
  8851. {
  8852. break;
  8853. }
  8854. }
  8855. else
  8856. {
  8857. DBGPRINT0(DET, "NmsDbDelDataRecs: There are no records to delete\n");
  8858. RetStat = WINS_SUCCESS;
  8859. break;
  8860. }
  8861. } while (TRUE);
  8862. } // end of try
  8863. finally {
  8864. JET_ERR JetRetStat;
  8865. DBGPRINT3(SCV, "NmsDbDelDataRecs: Deleted records of owner id = (%d) in the range (%x - %x)\n", dwOwnerId, MinVersNo, VersNo);
  8866. if (fEntered)
  8867. {
  8868. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  8869. }
  8870. //
  8871. // Change the index to clustered
  8872. //
  8873. JetRetStat = JetSetCurrentIndex(
  8874. pTls->SesId,
  8875. pTls->NamAddTblId,
  8876. NMSDB_NAM_ADD_CLUST_INDEX_NAME
  8877. );
  8878. if (!AbnormalTermination())
  8879. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  8880. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  8881. CALL_M(JetRetStat);
  8882. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  8883. } // end of finally
  8884. WinsEvtLogDetEvt(TRUE, WINS_EVT_DEL_RECS, NULL, __LINE__, "ddddd",
  8885. dwOwnerId, MinVersNo.LowPart, MinVersNo.HighPart,
  8886. VersNo.LowPart, VersNo.HighPart);
  8887. DBGPRINT1(DET, "NmsDbDelDataRecs: No. Of. records deleted = (%d)\n", NoOfRecsUpd);
  8888. DBGLEAVE("NmsDbDelDataRecs\n");
  8889. return(RetStat);
  8890. }
  8891. STATUS
  8892. NmsDbTombstoneDataRecs(
  8893. DWORD dwOwnerId,
  8894. VERS_NO_T MinVersNo,
  8895. VERS_NO_T MaxVersNo
  8896. )
  8897. /*++
  8898. Routine Description:
  8899. This function is called to tombstone a specified range of records
  8900. of a WINS from the local db
  8901. Arguments:
  8902. pWinsAdd - Address of owner WINS
  8903. MinVersNo - Min. Vers. No
  8904. MaxVersNo = Max. Vers. No
  8905. Externals Used:
  8906. None
  8907. Return Value:
  8908. Called by:
  8909. WinsTombstoneDbRecs
  8910. Side Effects:
  8911. Comments:
  8912. This function is called on RPC thread.
  8913. On exit, it sets the index to the clustered index on the
  8914. name-address table
  8915. --*/
  8916. {
  8917. JET_ERR JetRetStat;
  8918. DWORD ActFldLen; //length of fld retrieved
  8919. JET_TABLEID TblId;
  8920. JET_SESID SesId;
  8921. PWINSTHD_TLS_T pTls;
  8922. DWORD RecordOwnerId = 0;
  8923. DWORD NoOfRecsUpd = 0;
  8924. STATUS RetStat = WINS_SUCCESS;
  8925. BOOL fAllToBeTombstoned = FALSE;
  8926. DWORD Count = 0;
  8927. LONG RetVal;
  8928. BOOL fIncVersNo;
  8929. VERS_NO_T VersNo;
  8930. DWORD FlagVal;
  8931. BOOL LockHeld = FALSE;
  8932. BOOL UpdateOwnerId = FALSE;
  8933. DWORD_PTR NewTimeStamp;
  8934. time_t CurrentTime;
  8935. DWORD dwNewOwnerId;
  8936. DBGENTER("NmsDbTombstoneDataRecs\n");
  8937. GET_TLS_M(pTls);
  8938. ASSERT(pTls != NULL);
  8939. TblId = pTls->NamAddTblId;
  8940. SesId = pTls->SesId;
  8941. (void)time(&CurrentTime);
  8942. NewTimeStamp = CurrentTime + WinsCnf.TombstoneTimeout;
  8943. DBGPRINT1(DET, "NmsDbTombstoneDataRecs: The new tombstone Time is %.19s\n",
  8944. asctime(localtime(&NewTimeStamp)));
  8945. if (NMSDB_LOCAL_OWNER_ID != dwOwnerId) {
  8946. UpdateOwnerId = TRUE;
  8947. dwNewOwnerId = NMSDB_LOCAL_OWNER_ID;
  8948. }
  8949. // If both minimum and maximum version numbers specified are 0,
  8950. // it means all the records of the WINS need to be deleted
  8951. if (LiEqlZero(MinVersNo) && LiEqlZero(MaxVersNo)){
  8952. if (NMSDB_LOCAL_OWNER_ID == dwOwnerId) {
  8953. MaxVersNo = NmsNmhMyMaxVersNo;
  8954. } else {
  8955. fAllToBeTombstoned = TRUE;
  8956. }
  8957. }
  8958. CALL_N_JMP_M( JetSetCurrentIndex(
  8959. pTls->SesId,
  8960. pTls->NamAddTblId,
  8961. NMSDB_NAM_ADD_PRIM_INDEX_NAME
  8962. ),
  8963. Cleanup
  8964. );
  8965. CALL_N_JMP_M( JetMakeKey(
  8966. SesId,
  8967. TblId,
  8968. &dwOwnerId,
  8969. NAM_ADD_OWNERID_SIZE,
  8970. JET_bitNewKey //since this is the first
  8971. ),
  8972. Cleanup
  8973. );
  8974. CALL_N_JMP_M( JetMakeKey(
  8975. SesId,
  8976. TblId,
  8977. &MinVersNo,
  8978. sizeof(VERS_NO_T),
  8979. 0 //0 for grbit since this is not the
  8980. ),
  8981. Cleanup
  8982. );
  8983. JetRetStat = JetSeek(
  8984. SesId,
  8985. TblId,
  8986. JET_bitSeekGE
  8987. );
  8988. if (JetRetStat == JET_errRecordNotFound) {
  8989. DBGPRINT0(DET, "NmsDbTombstoneDataRecs: There are no records to tombstone\n");
  8990. RetStat = WINS_FAILURE;
  8991. goto Cleanup;
  8992. }
  8993. if (JetRetStat != JET_errSuccess && JetRetStat != JET_wrnSeekNotEqual) {
  8994. DBGPRINT1(ERR, "NmsDbTombstoneDataRecs: JetSeek failed with %ld\n",JetRetStat);
  8995. RetStat = WINS_FAILURE;
  8996. goto Cleanup;
  8997. }
  8998. while (TRUE) {
  8999. // tombstone 50 recs at a time so that we dont hold crit section
  9000. // for long time.
  9001. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  9002. LockHeld = TRUE;
  9003. do {
  9004. CALL_N_JMP_M(
  9005. JetRetrieveColumn(
  9006. SesId,
  9007. TblId,
  9008. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  9009. &RecordOwnerId,
  9010. NAM_ADD_OWNERID_SIZE,
  9011. &ActFldLen,
  9012. 0,
  9013. NULL),
  9014. Cleanup
  9015. );
  9016. if (RecordOwnerId != dwOwnerId ){
  9017. // We have exhausted all records for the owner. Break of the loop
  9018. goto Cleanup;
  9019. }
  9020. // Retrieve the version number
  9021. CALL_N_JMP_M(
  9022. JetRetrieveColumn(
  9023. SesId,
  9024. TblId,
  9025. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  9026. &VersNo,
  9027. sizeof(VERS_NO_T),
  9028. &ActFldLen,
  9029. 0,
  9030. NULL),
  9031. Cleanup
  9032. );
  9033. DBGPRINT2(DET, "NmsDbTombstoneDataRecs: tombstone record - (%lx - %lx)\n", VersNo.HighPart, VersNo.LowPart);
  9034. // If MaxVersNo is not zero and VersNo retrieved is
  9035. // greater than it, break out of the loop.
  9036. if (!fAllToBeTombstoned && LiGtr(VersNo, MaxVersNo)){
  9037. // We have acquired records upto MaxVersNo. Break of the loop
  9038. goto Cleanup;
  9039. }
  9040. // retrieve the flags column
  9041. CALL_N_JMP_M(
  9042. JetRetrieveColumn(
  9043. SesId,
  9044. TblId,
  9045. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  9046. &FlagVal,
  9047. sizeof(FlagVal),
  9048. &ActFldLen,
  9049. 0,
  9050. NULL
  9051. ),
  9052. Cleanup
  9053. );
  9054. CALL_N_JMP_M(JetBeginTransaction(SesId),Cleanup);
  9055. try {
  9056. CALL_N_RAISE_EXC_IF_ERR_M( JetPrepareUpdate(
  9057. SesId,
  9058. TblId,
  9059. JET_prepReplace
  9060. )
  9061. );
  9062. // make it tombstone.
  9063. NMSDB_SET_STATE_M(FlagVal,NMSDB_E_TOMBSTONE);
  9064. // Update the flags field
  9065. CALL_N_RAISE_EXC_IF_ERR_M( JetSetColumn(
  9066. SesId,
  9067. TblId,
  9068. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  9069. &FlagVal,
  9070. sizeof(FlagVal),
  9071. 0,
  9072. NULL /*optional info */
  9073. )
  9074. );
  9075. VersNo = NmsNmhMyMaxVersNo;
  9076. // Update the version number field so that this record gets
  9077. // propagated eventually
  9078. CALL_N_RAISE_EXC_IF_ERR_M( JetSetColumn(
  9079. SesId,
  9080. TblId,
  9081. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  9082. &VersNo,
  9083. sizeof(VERS_NO_T),
  9084. 0,
  9085. NULL /*optional info */
  9086. )
  9087. );
  9088. if (UpdateOwnerId) {
  9089. CALL_N_RAISE_EXC_IF_ERR_M( JetSetColumn(
  9090. SesId,
  9091. TblId,
  9092. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  9093. &dwNewOwnerId,
  9094. NAM_ADD_OWNERID_SIZE,
  9095. 0,
  9096. NULL /*optional info */
  9097. )
  9098. );
  9099. }
  9100. CALL_N_RAISE_EXC_IF_ERR_M( JetSetColumn(
  9101. SesId,
  9102. TblId,
  9103. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  9104. &NewTimeStamp,
  9105. sizeof(DWORD),
  9106. 0,
  9107. NULL /*optional info */
  9108. )
  9109. );
  9110. // Update the record
  9111. CALL_N_RAISE_EXC_IF_ERR_M(JetUpdate (
  9112. SesId,
  9113. TblId,
  9114. NULL,
  9115. 0L,
  9116. NULL
  9117. )
  9118. );
  9119. } // end of try block
  9120. finally {
  9121. if (AbnormalTermination()){
  9122. CALL_N_JMP_M(JetRollback(SesId,JET_bitRollbackAll), Cleanup);
  9123. }else{
  9124. CALL_N_JMP_M(JetCommitTransaction(SesId,JET_bitCommitFlush), Cleanup);
  9125. NMSNMH_INC_VERS_COUNTER_M(NmsNmhMyMaxVersNo,NmsNmhMyMaxVersNo);
  9126. NoOfRecsUpd++;
  9127. }
  9128. }
  9129. } while(((RetVal = JetMove(SesId, TblId, JET_MoveNext, 0)) >= 0)&&(++Count < 50));
  9130. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  9131. LockHeld = FALSE;
  9132. DBGPRINT2(SCV, "NmsDbTombstoneDataRecs: tombstoned records %ld, RetVal %ld, \n", Count, RetVal);
  9133. Count = 0;
  9134. if (RetVal < 0) {
  9135. break;
  9136. }
  9137. }
  9138. DBGPRINT3(SCV, "NmsDbTombstoneDataRecs: tombstone records of owner id = (%d) in the range (%x - %x)\n", dwOwnerId, MinVersNo, VersNo);
  9139. WinsEvtLogDetEvt(TRUE, WINS_EVT_DEL_RECS, NULL, __LINE__, "ddddd",
  9140. dwOwnerId, MinVersNo.LowPart, MinVersNo.HighPart,
  9141. VersNo.LowPart, VersNo.HighPart);
  9142. Cleanup:
  9143. // Change the index to clustered
  9144. JetSetCurrentIndex(
  9145. pTls->SesId,
  9146. pTls->NamAddTblId,
  9147. NMSDB_NAM_ADD_CLUST_INDEX_NAME
  9148. );
  9149. if (!LockHeld) {
  9150. EnterCriticalSection(&NmsNmhNamRegCrtSec);
  9151. }
  9152. if (NoOfRecsUpd) RPL_PUSH_NTF_M(RPL_PUSH_NO_PROP, NULL, NULL, NULL);
  9153. LeaveCriticalSection(&NmsNmhNamRegCrtSec);
  9154. DBGPRINT1(DET, "NmsDbTombstoneDataRecs: No. Of. records tombstoned = (%d)\n",NoOfRecsUpd);
  9155. DBGLEAVE("NmsDbTombstoneDataRecs\n");
  9156. return(RetStat);
  9157. }
  9158. STATUS
  9159. NmsDbSetFlushTime(
  9160. DWORD WaitTime
  9161. )
  9162. /*++
  9163. Routine Description:
  9164. This function is called to set a session specific flush time
  9165. Arguments:
  9166. WaitTime - Time in msecs to wait after a commit
  9167. Externals Used:
  9168. None
  9169. Return Value:
  9170. None
  9171. Error Handling:
  9172. Called by:
  9173. RplPullInit
  9174. Side Effects:
  9175. Comments:
  9176. None
  9177. --*/
  9178. {
  9179. PWINSTHD_TLS_T pTls;
  9180. GET_TLS_M(pTls);
  9181. ASSERT(pTls != NULL);
  9182. if (DynLoadJetVersion >= DYN_LOAD_JET_600) {
  9183. CALL_M(JetSetSystemParameter(
  9184. &sJetInstance,
  9185. pTls->SesId,
  9186. JET_paramWaitLogFlush,
  9187. WaitTime,
  9188. NULL //ignored
  9189. )
  9190. );
  9191. } else {
  9192. CALL_M(JetSetSystemParameter(
  9193. &sJetInstance,
  9194. pTls->SesId,
  9195. JET_paramWaitLogFlush_OLD,
  9196. WaitTime,
  9197. NULL //ignored
  9198. )
  9199. );
  9200. }
  9201. return(WINS_SUCCESS);
  9202. }
  9203. STATUS
  9204. NmsDbOpenTables(
  9205. WINS_CLIENT_E Client_e //client
  9206. )
  9207. /*++
  9208. Routine Description:
  9209. This function opens one or both of name-address mapping and
  9210. owner-address mapping tables. It further starts a transaction
  9211. Arguments:
  9212. Client_e - Client
  9213. Externals Used:
  9214. None
  9215. Return Value:
  9216. Success status codes --
  9217. Error status codes --
  9218. Error Handling:
  9219. Called by:
  9220. Side Effects:
  9221. Comments:
  9222. None
  9223. --*/
  9224. {
  9225. PWINSTHD_TLS_T pTls;
  9226. GET_TLS_M(pTls);
  9227. ASSERT(pTls != NULL);
  9228. //
  9229. // Open the name to address mapping table
  9230. //
  9231. CALL_N_RAISE_EXC_IF_ERR_M( JetOpenTable(
  9232. pTls->SesId,
  9233. pTls->DbId,
  9234. NMSDB_NAM_ADD_TBL_NM,
  9235. NULL, /*ptr to parameter list; should be
  9236. *non-NULL only if a query is being
  9237. *opened (not the case here)*/
  9238. 0, /*Length of above parameter list*/
  9239. 0, //shared access
  9240. &pTls->NamAddTblId
  9241. )
  9242. );
  9243. // DBGPRINT2(SPEC, "NmsDbOpenTables: OPENED NAME-ADD table for client = (%d). Table id is (%x)\n", Client_e, pTls->NamAddTblId);
  9244. pTls->fNamAddTblOpen = TRUE;
  9245. /*
  9246. * If the client is not the replicator (i.e. it is the Name Space
  9247. * Manager (Nbt thread) or an RPC thread, we want to set the current
  9248. * index on the Name Address Mapping table to the clustered index.
  9249. * We are not interested in the Owner to Address Mapping table in the
  9250. * database (it has already been read into the in-memory table
  9251. * NmsDbOwnAddTbl which is what we are interested in).
  9252. */
  9253. if (
  9254. (Client_e != WINS_E_RPLPULL)
  9255. &&
  9256. (Client_e != WINS_E_RPLPUSH)
  9257. &&
  9258. (Client_e != WINS_E_NMSSCV)
  9259. )
  9260. {
  9261. /*
  9262. Set the clustered index as the current index
  9263. */
  9264. CALL_N_RAISE_EXC_IF_ERR_M( JetSetCurrentIndex(
  9265. pTls->SesId,
  9266. pTls->NamAddTblId,
  9267. NMSDB_NAM_ADD_CLUST_INDEX_NAME
  9268. )
  9269. );
  9270. }
  9271. else
  9272. {
  9273. /*
  9274. * The client is a replicator thread.
  9275. */
  9276. if (Client_e == WINS_E_RPLPUSH)
  9277. {
  9278. /*
  9279. * Set the primary index as the current index
  9280. */
  9281. CALL_N_RAISE_EXC_IF_ERR_M( JetSetCurrentIndex(
  9282. pTls->SesId,
  9283. pTls->NamAddTblId,
  9284. NMSDB_NAM_ADD_PRIM_INDEX_NAME
  9285. )
  9286. );
  9287. }
  9288. else // it is the PULL thread
  9289. {
  9290. /*
  9291. *Set the clustered index as the current index
  9292. */
  9293. CALL_N_RAISE_EXC_IF_ERR_M( JetSetCurrentIndex(
  9294. pTls->SesId,
  9295. pTls->NamAddTblId,
  9296. NMSDB_NAM_ADD_CLUST_INDEX_NAME
  9297. )
  9298. );
  9299. }
  9300. CALL_N_RAISE_EXC_IF_ERR_M( JetOpenTable(
  9301. pTls->SesId,
  9302. pTls->DbId,
  9303. NMSDB_OWN_ADD_TBL_NM,
  9304. NULL, /*ptr to parameter list; should be
  9305. *non-NULL only if a query is being
  9306. *opened*/
  9307. 0, /*Length of above parameter list*/
  9308. 0, //shared access
  9309. &pTls->OwnAddTblId
  9310. )
  9311. );
  9312. // DBGPRINT2(SPEC, "NmsDbOpenTables: Opened OWN-ADD table for client = (%d). Table id is (%x)\n", Client_e, pTls->OwnAddTblId);
  9313. pTls->fOwnAddTblOpen = TRUE;
  9314. /*
  9315. Set the clustered index as the current index
  9316. */
  9317. CALL_N_RAISE_EXC_IF_ERR_M( JetSetCurrentIndex(
  9318. pTls->SesId,
  9319. pTls->OwnAddTblId,
  9320. NMSDB_OWN_ADD_CLUST_INDEX_NAME
  9321. )
  9322. );
  9323. }
  9324. return(WINS_SUCCESS);
  9325. }
  9326. STATUS
  9327. NmsDbCloseTables(
  9328. VOID
  9329. )
  9330. /*++
  9331. Routine Description:
  9332. This function is called to close the tables that were opened
  9333. Arguments:
  9334. None
  9335. Externals Used:
  9336. None
  9337. Return Value:
  9338. None
  9339. Error Handling:
  9340. Called by:
  9341. Side Effects:
  9342. Comments:
  9343. None
  9344. --*/
  9345. {
  9346. PWINSTHD_TLS_T pTls;
  9347. GET_TLS_M(pTls);
  9348. ASSERT(pTls != NULL);
  9349. if (pTls->fNamAddTblOpen)
  9350. {
  9351. CALL_N_RAISE_EXC_IF_ERR_M(JetCloseTable(
  9352. pTls->SesId,
  9353. pTls->NamAddTblId
  9354. )
  9355. );
  9356. // DBGPRINT1(SPEC, "NmsDbCloseTables: CLOSED NAME-ADD table. Table id is (%x)\n", pTls->NamAddTblId);
  9357. pTls->fNamAddTblOpen = FALSE;
  9358. }
  9359. if (pTls->fOwnAddTblOpen)
  9360. {
  9361. CALL_N_RAISE_EXC_IF_ERR_M(JetCloseTable(
  9362. pTls->SesId,
  9363. pTls->OwnAddTblId
  9364. )
  9365. );
  9366. // DBGPRINT1(SPEC, "NmsDbCloseTables: CLOSED NAME-ADD table. Table id is (%x)\n", pTls->OwnAddTblId);
  9367. pTls->fOwnAddTblOpen = FALSE;
  9368. }
  9369. return(WINS_SUCCESS);
  9370. }
  9371. STATUS
  9372. NmsDbGetNamesWPrefixChar(
  9373. IN BYTE PrefixChar,
  9374. OUT PWINSINTF_BROWSER_INFO_T *ppInfo,
  9375. OUT LPDWORD pEntriesRead
  9376. )
  9377. /*++
  9378. Routine Description:
  9379. This function retrieves all records starting with PrefixChar
  9380. Arguments:
  9381. PrefixChar - Prefix character
  9382. ppInfo - address of pointer to info structure
  9383. pEntriesRead - Entries read
  9384. Externals Used:
  9385. None
  9386. Return Value:
  9387. Success status codes -- WINS_SUCCESS
  9388. Error status codes -- WINS_FAILURE
  9389. Error Handling:
  9390. Called by:
  9391. WinsGetNames
  9392. Side Effects:
  9393. Comments:
  9394. None
  9395. --*/
  9396. {
  9397. PWINSTHD_TLS_T pTls;
  9398. volatile DWORD Iter = 0;
  9399. JET_SESID SesId;
  9400. JET_TABLEID TblId;
  9401. JET_ERR JetRetStat;
  9402. DWORD Flag;
  9403. DWORD ActFldLen; //length of fld retrieved
  9404. PWINSINTF_BROWSER_INFO_T pInfo;
  9405. STATUS RetStat = WINS_SUCCESS;
  9406. DWORD CommitCnt = 1; //the number of commits already done - do not change
  9407. BOOL fTransCommitted = TRUE; // says whether the last commit should be done or not
  9408. DWORD dwEntriesAvailable; // number of records for which storage is available
  9409. DBGENTER("NmsDbGetNamesWPrefixChar\n");
  9410. //
  9411. // Initialize the out args to default values
  9412. //
  9413. *pEntriesRead = 0;
  9414. *ppInfo = NULL;
  9415. GET_TLS_M(pTls);
  9416. ASSERT(pTls != NULL);
  9417. SesId = pTls->SesId;
  9418. TblId = pTls->NamAddTblId;
  9419. CALL_M(JetBeginTransaction(SesId));
  9420. fTransCommitted = FALSE;
  9421. try {
  9422. // dwEntriesAvailable shows how many records were found during the first iteration
  9423. // (when it is incremented) and how many records are to be read during the second
  9424. // iteration (when it is decremented)
  9425. dwEntriesAvailable = 0;
  9426. //
  9427. // We iterate a max of two times, the first time to get the
  9428. // count of records and the second time to get the records
  9429. //
  9430. while(Iter < 2)
  9431. {
  9432. //
  9433. // Seek to the first record starting with 1B character
  9434. //
  9435. CALL_N_JMP_M( JetMakeKey(
  9436. SesId,
  9437. TblId,
  9438. &PrefixChar,
  9439. sizeof(BYTE),
  9440. JET_bitNewKey
  9441. ), ErrorProc
  9442. );
  9443. if ((JetRetStat = JetSeek(
  9444. SesId,
  9445. TblId,
  9446. JET_bitSeekGE
  9447. )) != JET_errRecordNotFound)
  9448. {
  9449. BYTE Name[NMSDB_MAX_NAM_LEN];
  9450. DWORD NameLen;
  9451. if (JetRetStat != JET_wrnSeekNotEqual)
  9452. {
  9453. CALL_N_JMP_M(JetRetStat, ErrorProc);
  9454. }
  9455. //
  9456. // Move one record at a time until we get to a record that
  9457. // does not have 1B as the starting prefix.
  9458. //
  9459. do
  9460. {
  9461. BOOL bFiltered;
  9462. //
  9463. // retrieve the name
  9464. //
  9465. CALL_N_JMP_M( JetRetrieveColumn(
  9466. SesId,
  9467. TblId,
  9468. sNamAddTblRow[NAM_ADD_NAME_INDEX].Fid,
  9469. Name,
  9470. NMSDB_MAX_NAM_LEN,
  9471. &NameLen,
  9472. 0,
  9473. NULL
  9474. ), ErrorProc
  9475. );
  9476. //
  9477. // Check if the first character is 1B
  9478. //
  9479. if (Name[0] != PrefixChar)
  9480. {
  9481. break;
  9482. }
  9483. if ((NameLen < WINS_MAX_NS_NETBIOS_NAME_LEN) || (Name[NameLen - 2] == 0))
  9484. {
  9485. continue;
  9486. }
  9487. // --ft:10/18/00
  9488. // Add 1B name filtering here, if there is a filter specified for 1B names
  9489. //
  9490. EnterCriticalSection(&g_cs1BFilter);
  9491. bFiltered = IsNmInFilter(g_p1BFilter, Name, WINS_MAX_NS_NETBIOS_NAME_LEN-1);
  9492. LeaveCriticalSection(&g_cs1BFilter);
  9493. if (!bFiltered)
  9494. continue;
  9495. //
  9496. // --tf
  9497. if (Iter == 1)
  9498. {
  9499. //
  9500. // Retrieve the flag byte
  9501. //
  9502. CALL_N_JMP_M( JetRetrieveColumn(
  9503. SesId,
  9504. TblId,
  9505. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  9506. &Flag,
  9507. sizeof(Flag),
  9508. &ActFldLen,
  9509. 0,
  9510. NULL
  9511. ), ErrorProc
  9512. );
  9513. if (!NMSDB_ENTRY_ACT_M(Flag))
  9514. {
  9515. continue;
  9516. }
  9517. // specify the length of the string otherwise RPC
  9518. // will transport up to the first '\0'. For shorter names this would lead
  9519. // to loosing the record type on the way..
  9520. pInfo->dwNameLen = NameLen;
  9521. pInfo->pName = midl_user_allocate(NameLen + 1);
  9522. RtlMoveMemory(pInfo->pName, Name, NameLen);
  9523. // add this to make sure RPC doesn't go over limits.
  9524. // RPC is seeing pName as 'string' which makes it to pick up bytes
  9525. // up to the first '\0'.
  9526. // This hides a bug for names that contain extended chars (with '\0'
  9527. // somewhere in the middle) but fixing this breaks compatibility with
  9528. // Win2K (querying Win2K results in RPC not being able to unmarshall
  9529. // the responses and causing WinsGetBrowser to fail entirely).
  9530. pInfo->pName[NameLen] = '\0';
  9531. //
  9532. // Swap the first and 16th byte
  9533. //
  9534. WINS_SWAP_BYTES_M(pInfo->pName,
  9535. pInfo->pName + 15
  9536. );
  9537. pInfo++;
  9538. // increment the number of records that have been retrieved
  9539. (*pEntriesRead)++;
  9540. // check if there remains storage for more entries
  9541. dwEntriesAvailable--;
  9542. // if no memory available, break the loop
  9543. if (dwEntriesAvailable == 0)
  9544. break;
  9545. }
  9546. else
  9547. {
  9548. dwEntriesAvailable++;
  9549. // increment pEntriesRead here just to be able to control
  9550. // the granularity of [BeginTransaction()..CommitTransaction()] during both
  9551. // iterations
  9552. (*pEntriesRead)++;
  9553. }
  9554. //
  9555. // decrease the granularity of [BeginTransaction()..CommitTransaction()] intervals
  9556. //
  9557. if (*pEntriesRead/CommitCnt >= MAX_RECS_BEFORE_COMMIT)
  9558. {
  9559. CALL_M(
  9560. JetCommitTransaction(SesId, JET_bitCommitFlush)
  9561. );
  9562. fTransCommitted = TRUE;
  9563. CommitCnt++;
  9564. CALL_M( JetBeginTransaction(SesId) );
  9565. fTransCommitted = FALSE;
  9566. }
  9567. } while(JetMove(SesId, TblId, JET_MoveNext, 0) >= 0);
  9568. //
  9569. // If we found records, allocate memory to store them
  9570. //
  9571. if ((Iter == 0) && (dwEntriesAvailable != 0))
  9572. {
  9573. *ppInfo = midl_user_allocate(dwEntriesAvailable *
  9574. sizeof(WINSINTF_BROWSER_INFO_T));
  9575. pInfo = *ppInfo;
  9576. // reset the pEntriesRead, as from now on it will really count the records that have been retrieved.
  9577. *pEntriesRead = 0;
  9578. }
  9579. else
  9580. {
  9581. // either two iterations already done, or no entries detected during the first iteration.
  9582. // break the loop in either case, otherwise AV could happen or even worse, other locations
  9583. // from the memory space of the same process might get overwritten.
  9584. break;
  9585. }
  9586. Iter++;
  9587. }
  9588. else
  9589. {
  9590. //
  9591. // If we failed in the first seek, initialize the out vars
  9592. // to indicate that there are no records. If we failed in
  9593. // the second seek, set return status to WINS_FAILURE, so
  9594. // that we do any cleanup that is required
  9595. //
  9596. if (Iter == 0)
  9597. {
  9598. *pEntriesRead = 0;
  9599. *ppInfo = NULL;
  9600. }
  9601. else
  9602. {
  9603. RetStat = WINS_FAILURE;
  9604. }
  9605. break; //break out of the while loop
  9606. }
  9607. //
  9608. // if no entries were read from the db, break;
  9609. //
  9610. if (dwEntriesAvailable == 0)
  9611. {
  9612. break;
  9613. }
  9614. } // end of while
  9615. }
  9616. except(EXCEPTION_EXECUTE_HANDLER) {
  9617. DWORD ExcCode = GetExceptionCode();
  9618. DBGPRINT1(EXC, "NmsDbGetNamesWPrefixChar. Got Exception (%x)",
  9619. ExcCode);
  9620. WINSEVT_LOG_M(ExcCode, WINS_EVT_BROWSER_NAME_EXC);
  9621. RetStat = WINS_FAILURE;
  9622. }
  9623. if (RetStat == WINS_SUCCESS)
  9624. {
  9625. goto Done;
  9626. }
  9627. ErrorProc:
  9628. //
  9629. // if memory was allocated, do cleanup
  9630. //
  9631. if (*ppInfo != NULL)
  9632. {
  9633. //
  9634. // If any memory was allocated for names, free it
  9635. //
  9636. pInfo = *ppInfo;
  9637. while (*pEntriesRead > 0)
  9638. {
  9639. midl_user_free(pInfo++->pName);
  9640. (*pEntriesRead)--;
  9641. }
  9642. //
  9643. // Free the main block
  9644. //
  9645. midl_user_free(*ppInfo);
  9646. //
  9647. // Reinit the out args to indicate no records to the client
  9648. //
  9649. *ppInfo = NULL;
  9650. *pEntriesRead = 0;
  9651. }
  9652. RetStat = WINS_FAILURE;
  9653. Done:
  9654. if (!fTransCommitted)
  9655. CALL_M(JetCommitTransaction(SesId, JET_bitCommitFlush));
  9656. DBGLEAVE("NmsDbGetNamesWPrefixChar\n");
  9657. return(RetStat);
  9658. } // NmsDbGetNamesWPrefixChar
  9659. STATUS
  9660. NmsDbCleanupOwnAddTbl(
  9661. LPDWORD pNoOfOwners
  9662. )
  9663. /*++
  9664. Routine Description:
  9665. This function is called by the scavenger thread to cleanup
  9666. the OwnAdd Table
  9667. Arguments:
  9668. SesId - Jet Session id
  9669. TblId - Table Id of the Name-Address Mapping table
  9670. Externals Used:
  9671. None
  9672. Return Value:
  9673. Success status codes --
  9674. Error status codes --
  9675. Error Handling:
  9676. Called by:
  9677. NmsDbInit
  9678. Side Effects:
  9679. Comments:
  9680. This function returns the highest owner id found.
  9681. --*/
  9682. {
  9683. DWORD OwnerId;
  9684. #if NEW_OWID
  9685. DWORD TmpOwnerId;
  9686. #else
  9687. DWORD TmpOwnerId = 0;
  9688. #endif
  9689. DWORD ActFldLen;
  9690. JET_ERR JetRetStat;
  9691. PWINSTHD_TLS_T pTls;
  9692. JET_SESID SesId;
  9693. JET_TABLEID TblId;
  9694. BOOL fNoOfOwnersInited = FALSE;
  9695. DWORD No;
  9696. STATUS RetStat = WINS_SUCCESS;
  9697. DBGENTER("NmsDbCleanupOwnAddTbl\n");
  9698. GET_TLS_M(pTls);
  9699. ASSERT(pTls != NULL);
  9700. SesId = pTls->SesId;
  9701. TblId = pTls->NamAddTblId;
  9702. /*
  9703. * Set the primary index as the current index
  9704. */
  9705. CALL_N_RAISE_EXC_IF_ERR_M( JetSetCurrentIndex(
  9706. SesId,
  9707. TblId,
  9708. NMSDB_NAM_ADD_PRIM_INDEX_NAME
  9709. )
  9710. );
  9711. EnterCriticalSection(&NmsDbOwnAddTblCrtSec);
  9712. *pNoOfOwners = NmsDbNoOfOwners;
  9713. try {
  9714. OwnerId = NmsDbNoOfOwners;
  9715. do
  9716. {
  9717. DBGPRINT1(FLOW, "NmsDbCleanupOwnAddTbl: will seek for owner less than = (%d)\n", OwnerId);
  9718. //
  9719. // Construct a partial key made of owner id.
  9720. //
  9721. CALL_N_RAISE_EXC_IF_ERR_M( JetMakeKey(
  9722. SesId,
  9723. TblId,
  9724. &OwnerId,
  9725. NAM_ADD_OWNERID_SIZE,
  9726. JET_bitNewKey //since this is the first
  9727. //data value of the key
  9728. )
  9729. );
  9730. //
  9731. // Seek to the record that has a key that is Less than or
  9732. // Equal to the OwnerId value.
  9733. //
  9734. // Since we have specified a partial key (saying in effect
  9735. // that the other component of the key is NULL), JetSeek
  9736. // must return wrnSeekNotEqual since it will never find
  9737. // a record with NULL for the second component of the index
  9738. // -- Ian 7/13/93
  9739. //
  9740. JetRetStat = JetSeek(
  9741. SesId,
  9742. TblId,
  9743. JET_bitSeekLE
  9744. );
  9745. //
  9746. // If we found a record
  9747. //
  9748. if (JetRetStat != JET_errRecordNotFound)
  9749. {
  9750. ASSERT(JetRetStat == JET_wrnSeekNotEqual);
  9751. /*
  9752. * Retrieve the owner Id column.
  9753. */
  9754. CALL_N_RAISE_EXC_IF_ERR_M(
  9755. JetRetrieveColumn(
  9756. SesId,
  9757. TblId,
  9758. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  9759. &TmpOwnerId,
  9760. NAM_ADD_OWNERID_SIZE,
  9761. &ActFldLen,
  9762. JET_bitRetrieveFromIndex,
  9763. NULL
  9764. )
  9765. );
  9766. if(!fNoOfOwnersInited)
  9767. {
  9768. //
  9769. // We want to return the highest owner id that we find.
  9770. // not the number of owners. The param. name is
  9771. // misleading
  9772. //
  9773. *pNoOfOwners = TmpOwnerId;
  9774. fNoOfOwnersInited = TRUE;
  9775. }
  9776. DBGPRINT1(FLOW, "NmsDbCleanupOwnAddTbl: records found for owner id = (%d)\n", TmpOwnerId);
  9777. //
  9778. // Mark all those records in the owner-address table
  9779. // that don't have corresponding records in the
  9780. // name - address table
  9781. //
  9782. if (OwnerId >= 1)
  9783. {
  9784. for (No = OwnerId - 1; No > TmpOwnerId; No--)
  9785. {
  9786. if ((pNmsDbOwnAddTbl+No)->WinsState_e ==
  9787. NMSDB_E_WINS_ACTIVE)
  9788. {
  9789. //
  9790. // We may have deleted this entry in an earlier
  9791. // invocation. If so, we bypass the deletion here.
  9792. //
  9793. if ((pNmsDbOwnAddTbl+No)->WinsState_e !=
  9794. NMSDB_E_WINS_DELETED)
  9795. {
  9796. DBGPRINT1(FLOW, "NmsDbCleanupOwnAddTbl: Deleting WINS with owner id = (%d)\n", No);
  9797. (pNmsDbOwnAddTbl+No)->WinsState_e = NMSDB_E_WINS_DELETED;
  9798. NmsDbWriteOwnAddTbl(
  9799. NMSDB_E_DELETE_REC,
  9800. No,
  9801. NULL,
  9802. NMSDB_E_WINS_DELETED,
  9803. NULL,
  9804. NULL
  9805. );
  9806. }
  9807. else
  9808. {
  9809. DBGPRINT1(DET, "NmsDbCleanupOwnAddTbl: Owner Id (%d) is already in DELETED state\n", OwnerId);
  9810. }
  9811. }
  9812. }
  9813. //
  9814. // Make OwnerId = the max owner id that we found.
  9815. //
  9816. OwnerId = TmpOwnerId;
  9817. }
  9818. else
  9819. {
  9820. //
  9821. // Owner Id is 0, our job is done
  9822. //
  9823. break;
  9824. }
  9825. }
  9826. else //record not found
  9827. {
  9828. if(!fNoOfOwnersInited)
  9829. {
  9830. //
  9831. // Since fNoOfOwnersInited is FALSE, we
  9832. // did not find even one record
  9833. //
  9834. DBGPRINT1(FLOW, "NmsDbCleanupOwnAddTbl: THERE IS NOT EVEN ONE REPLICA RECORD IN THE DB. No of owners in Own-Add Tbl are (%d)\n",
  9835. NmsDbNoOfOwners
  9836. )
  9837. *pNoOfOwners = 0;
  9838. }
  9839. if (OwnerId > 0)
  9840. {
  9841. for (No = OwnerId - 1; No > 0; No--)
  9842. {
  9843. DBGPRINT1(FLOW, "NmsDbCleanupOwnAddTbl: Deleting WINS with owner id = (%d)\n", No);
  9844. if ((pNmsDbOwnAddTbl+No)->WinsState_e ==
  9845. NMSDB_E_WINS_ACTIVE)
  9846. {
  9847. (pNmsDbOwnAddTbl+No)->WinsState_e =
  9848. NMSDB_E_WINS_DELETED;
  9849. NmsDbWriteOwnAddTbl(
  9850. NMSDB_E_DELETE_REC,
  9851. No,
  9852. NULL,
  9853. NMSDB_E_WINS_DELETED,
  9854. NULL,
  9855. NULL
  9856. );
  9857. }
  9858. } // end of for
  9859. }
  9860. //
  9861. // No more records in the db. Break out of the loop
  9862. //
  9863. break;
  9864. }
  9865. } while (TRUE);
  9866. } // end of try
  9867. except(EXCEPTION_EXECUTE_HANDLER) {
  9868. DWORD ExcCode = GetExceptionCode();
  9869. DBGPRINT1(EXC, "NmsDbCleanupOwnAddTbl: Got exception (%x)\n", ExcCode);
  9870. WINSEVT_LOG_M(ExcCode, WINS_EVT_CLEANUP_OWNADDTBL_EXC);
  9871. RetStat = WINS_FAILURE;
  9872. }
  9873. LeaveCriticalSection(&NmsDbOwnAddTblCrtSec);
  9874. DBGLEAVE("NmsDbCleanupOwnAddTbl\n");
  9875. return(RetStat);
  9876. }
  9877. STATUS
  9878. NmsDbBackup(
  9879. LPBYTE pBackupPath,
  9880. DWORD TypeOfBackup
  9881. )
  9882. /*++
  9883. Routine Description:
  9884. This function is called to backup the jet db
  9885. Arguments:
  9886. pBackupPath - backup dir
  9887. fIncremental - indicates whether the backup is incremental/full
  9888. Externals Used:
  9889. None
  9890. Return Value:
  9891. Success status codes --
  9892. Error status codes --
  9893. Error Handling:
  9894. Called by:
  9895. Side Effects:
  9896. Comments:
  9897. None
  9898. --*/
  9899. {
  9900. JET_ERR JetRetStat;
  9901. DWORD RetStat = WINS_SUCCESS;
  9902. static BOOL sFullBackupDone = FALSE;
  9903. BOOL fBackupChanged = FALSE;
  9904. DBGENTER("NmsDbBackup\n");
  9905. if (pBackupPath != NULL)
  9906. {
  9907. DBGPRINT2(FLOW, "NmsDbBackup:Backup path = (%s).\n Type of Backup = (%s)\n", pBackupPath, TypeOfBackup == NMSDB_FULL_BACKUP ? "FULL" : "INCREMENTAL");
  9908. }
  9909. else
  9910. {
  9911. DBGPRINT0(FLOW, "NmsDbBackup. Null Backup path\n");
  9912. }
  9913. //
  9914. // If we have to do an incremental backup to a non-null directory and we
  9915. // haven't ever done a full back in this instance of WINS, we do a full
  9916. // backup
  9917. //
  9918. if ((pBackupPath != NULL) && (TypeOfBackup != NMSDB_FULL_BACKUP) && !sFullBackupDone)
  9919. {
  9920. TypeOfBackup = NMSDB_FULL_BACKUP;
  9921. fBackupChanged = TRUE;
  9922. }
  9923. if (DynLoadJetVersion >= DYN_LOAD_JET_500)
  9924. {
  9925. JetRetStat = JetBackup(pBackupPath, (ULONG)TypeOfBackup, NULL);
  9926. }
  9927. else
  9928. {
  9929. JetRetStat = JetBackup(pBackupPath, (ULONG)TypeOfBackup);
  9930. }
  9931. if (JetRetStat != JET_errSuccess)
  9932. {
  9933. DBGPRINT3(ERR, "NmsDbBackup: Could not do %s backup to dir (%s). Error from JetBackup is (%d)\n", TypeOfBackup == NMSDB_FULL_BACKUP ? "FULL" : "INCREMENTAL", pBackupPath, JetRetStat);
  9934. WinsEvtLogDetEvt(FALSE, WINS_EVT_BACKUP_ERR, NULL, __LINE__,
  9935. "sd", pBackupPath, JetRetStat);
  9936. RetStat = WINS_FAILURE;
  9937. }
  9938. else
  9939. {
  9940. //
  9941. // Backup was successful. Let us set the static flag to indicate that.
  9942. //
  9943. if (fBackupChanged)
  9944. {
  9945. sFullBackupDone = TRUE;
  9946. fBackupChanged = FALSE;
  9947. }
  9948. }
  9949. DBGLEAVE("NmsDbBackup\n");
  9950. return(RetStat);
  9951. }
  9952. STATUS
  9953. NmsDbGetDataRecsByName(
  9954. LPBYTE pName,
  9955. DWORD NameLen,
  9956. DWORD Location,
  9957. DWORD NoOfRecsDesired,
  9958. PCOMM_ADD_T pWinsAdd,
  9959. DWORD TypeOfRecs,
  9960. LPVOID *ppRBuf,
  9961. LPDWORD pRspBuffLen,
  9962. LPDWORD pNoOfRecsRet
  9963. )
  9964. /*++
  9965. Routine Description:
  9966. Arguments:
  9967. Externals Used:
  9968. None
  9969. Return Value:
  9970. Success status codes --
  9971. Error status codes --
  9972. Error Handling:
  9973. Called by:
  9974. Side Effects:
  9975. Comments:
  9976. None
  9977. --*/
  9978. {
  9979. JET_ERR JetRetStat = JET_errSuccess;
  9980. DWORD OwnerId;
  9981. DWORD ActFldLen; //length of fld retrieved
  9982. VERS_NO_T TmpNoOfEntries;
  9983. LPBYTE pStartBuff;
  9984. DWORD SaveBufLen;
  9985. BYTE EntTyp; //type of entry (unique/group/special group)
  9986. PRPL_REC_ENTRY2_T pRspBuf;
  9987. JET_TABLEID TblId;
  9988. JET_SESID SesId;
  9989. PWINSTHD_TLS_T pTls;
  9990. #if NEW_OWID
  9991. DWORD RecordOwnerId;
  9992. #else
  9993. DWORD RecordOwnerId = 0;
  9994. #endif
  9995. STATUS RetStat = WINS_SUCCESS;
  9996. BYTE Name[NMSDB_MAX_NAM_LEN];
  9997. DWORD InitHeapSize;
  9998. LONG MoveDir = JET_MoveNext;
  9999. DWORD MemSize;
  10000. #ifdef WINSDBG
  10001. DWORD StartTime;
  10002. DWORD EndTime;
  10003. #endif
  10004. BOOL fAllocNew;
  10005. BOOL fTransCommitted = TRUE; // says whether the last commit should be done or not
  10006. DWORD CommitCnt = 1; //the number of commits already done - do not change
  10007. DBGENTER("NmsDbGetDataRecsByName\n");
  10008. GET_TLS_M(pTls);
  10009. ASSERT(pTls != NULL);
  10010. TblId = pTls->NamAddTblId;
  10011. SesId = pTls->SesId;
  10012. #ifdef WINSDBG
  10013. if (pWinsAdd != NULL)
  10014. {
  10015. struct in_addr InAddr;
  10016. InAddr.s_addr = htonl(pWinsAdd->Add.IPAdd);
  10017. DBGPRINT3(DET, "NmsDbGetDataRecsByName:Will retrieve %d records starting from record with name (%s) of WINS having address = (%s)\n",
  10018. NoOfRecsDesired, pName, inet_ntoa(InAddr) );
  10019. }
  10020. else
  10021. {
  10022. DBGPRINT2(DET, "NmsDbGetDataRecsByName:Will retrieve %d records starting from record with name (%s)\n", NoOfRecsDesired, pName);
  10023. }
  10024. #endif
  10025. //
  10026. // initialize the default no. that determines the size of the
  10027. // buffer to allocate in case the range specified by the Max and
  10028. // Min Vers. No args is > it
  10029. //
  10030. PERF("Move this to NmsDbInit")
  10031. WINS_ASSIGN_INT_TO_VERS_NO_M(TmpNoOfEntries, NoOfRecsDesired);
  10032. pTls->HeapHdl = NULL; //make it NULL so that the caller can determine
  10033. //whether this function allocated a heap
  10034. //before returning (normally/abnormally)
  10035. //
  10036. // Store the memory size for the records. Note: This
  10037. // does not contain the memory for the name and addresses
  10038. // (in case of a special group or a multihomed entry). The
  10039. // sizes for these will be added as we store each record.
  10040. //
  10041. // MemSize = RPL_REC_ENTRY_SIZE * (TmpNoOfEntries.LowPart + 1);
  10042. MemSize = RPL_REC_ENTRY2_SIZE * (DWORD)(TmpNoOfEntries.QuadPart + 1);
  10043. *pRspBuffLen = MemSize + 10000; //for good measure;
  10044. //
  10045. // We will create a heap with the above amount of memory plus a
  10046. // pad for heap overhead. We add TmpNoOfEntries.LowPart * 17
  10047. // since each record will have memory allocated for the name.
  10048. // Names in general will be 17 bytes long (we attach a NULL at the
  10049. // end when registering names).
  10050. //
  10051. // InitHeapSize = *pRspBuffLen + (TmpNoOfEntries.LowPart * 17)
  10052. InitHeapSize = *pRspBuffLen + ((DWORD)(TmpNoOfEntries.QuadPart * 17)
  10053. + PAD_FOR_REC_HEAP);
  10054. //
  10055. // Create the heap
  10056. //
  10057. pTls->HeapHdl = WinsMscHeapCreate(0, InitHeapSize);
  10058. pRspBuf = WinsMscHeapAlloc(pTls->HeapHdl, MemSize);
  10059. pStartBuff = (LPBYTE)pRspBuf; //save start of buffer
  10060. SaveBufLen = MemSize; //save size of buffer
  10061. *pNoOfRecsRet = 0;
  10062. *ppRBuf = pStartBuff;
  10063. //
  10064. // Actually, we can call RplFindOwnerId for Scavenger thread
  10065. // We choose not to do so to avoid some overhead -- see the
  10066. // comment in the else block.
  10067. //
  10068. if (pWinsAdd != NULL)
  10069. {
  10070. fAllocNew = FALSE;
  10071. try {
  10072. if (RplFindOwnerId(
  10073. pWinsAdd,
  10074. &fAllocNew,
  10075. &OwnerId,
  10076. WINSCNF_E_IGNORE_PREC,
  10077. WINSCNF_LOW_PREC
  10078. ) != WINS_SUCCESS
  10079. )
  10080. {
  10081. //
  10082. // The client may not look at the return value, but
  10083. // it will look at the *pNoOfRecs value and thus
  10084. // determine that there are no records.
  10085. //
  10086. return(WINS_FAILURE);
  10087. }
  10088. }
  10089. except(EXCEPTION_EXECUTE_HANDLER) {
  10090. DWORD ExcCode = GetExceptionCode();
  10091. DBGPRINT1(EXC,
  10092. "NmsDbGetDataRecsByName: Got exception %x",
  10093. ExcCode);
  10094. WINSEVT_LOG_M(ExcCode, WINS_EVT_EXC_RETRIEVE_DATA_RECS);
  10095. return(WINS_FAILURE);
  10096. }
  10097. //
  10098. //It is ok not to enter a critical section here since even if
  10099. //the array entry is being changed at this time, the repercussion
  10100. // of us seeing the old value is insignificant
  10101. //
  10102. if ((OwnerId != NMSDB_LOCAL_OWNER_ID) && LiEqlZero((pRplPullOwnerVersNo+OwnerId)->VersNo))
  10103. {
  10104. DBGPRINT2(DET, "NmsDbGetDataRecsByName: WINS with address = (%x) and owner id = (%d) has 0 records in the db\n", pWinsAdd->Add.IPAdd, OwnerId);
  10105. return(WINS_SUCCESS);
  10106. }
  10107. }
  10108. /*
  10109. * start a transaction
  10110. */
  10111. CALL_M(JetBeginTransaction(pTls->SesId));
  10112. fTransCommitted = FALSE;
  10113. try {
  10114. if ((pName != NULL) || ((pName == NULL) && (Location != WINSINTF_END)))
  10115. {
  10116. CALL_M( JetMakeKey(
  10117. SesId,
  10118. TblId,
  10119. pName,
  10120. NameLen,
  10121. JET_bitNewKey
  10122. )
  10123. );
  10124. JetRetStat = JetSeek( SesId, TblId, JET_bitSeekGE);
  10125. if (
  10126. (JetRetStat == JET_errRecordNotFound)
  10127. ||
  10128. ((JetRetStat != JET_errSuccess) && (JetRetStat != JET_wrnSeekNotEqual))
  10129. )
  10130. {
  10131. //DBGPRINT0(ERR, "Weird. Could not locate even one record\n");
  10132. //WINSEVT_LOG_M(WINS_FAILURE,WINS_EVT_CANT_FIND_ANY_REC_IN_RANGE);
  10133. //
  10134. // Don't free memory. It will get freed later.
  10135. //
  10136. //
  10137. // Don't use macro CALL_M since that will call return
  10138. // which will cause overhead since the system will
  10139. // search for a termination handler. We don't want
  10140. // that for the case where there are no records in the db
  10141. //
  10142. if (JetRetStat != JET_errRecordNotFound)
  10143. {
  10144. #ifdef WINSDBG
  10145. DBGPRINT2(ERR, "Jet Error: JetRetStat is (%d). Line is (%d)\n",
  10146. JetRetStat, __LINE__);
  10147. #endif
  10148. WINSEVT_LOG_D_M(JetRetStat, WINS_EVT_DATABASE_ERR);
  10149. RetStat = WINS_FAILURE;
  10150. }
  10151. }
  10152. }
  10153. else
  10154. {
  10155. CALL_M(JetMove(
  10156. SesId,
  10157. TblId,
  10158. JET_MoveLast,
  10159. //Location == WINSINTF_END ? JET_MoveLast : JET_MoveFirst,
  10160. 0)
  10161. );
  10162. }
  10163. CHECK("Check with IAN JOSE")
  10164. //
  10165. // We are assured of there being at least one record since the
  10166. // JetSeek succeeded (if not for the owner we are interested in
  10167. // then for the next one).
  10168. // We can therefore safely use the do .. while() construct
  10169. //
  10170. // *NOT REALLY. It seems that JetSeek can return JET_wrnSeekNE
  10171. // even when there are no records in the db. In such a case,
  10172. // our JetRetrieveColumn will fail with a CurrencyNot there error
  10173. //
  10174. //
  10175. // If we found an exact match or a name greater than the search string,
  10176. // retrieve the record.
  10177. //
  10178. if ((RetStat == WINS_SUCCESS) && (JetRetStat != JET_errRecordNotFound))
  10179. {
  10180. if (Location == WINSINTF_END)
  10181. {
  10182. MoveDir = JET_MovePrevious;
  10183. }
  10184. #ifdef WINSDBG
  10185. //(void)time(&StartTime);
  10186. StartTime = GetTickCount();
  10187. #endif
  10188. do
  10189. {
  10190. CALL_M(JetRetrieveColumn(
  10191. SesId,
  10192. TblId,
  10193. sNamAddTblRow[NAM_ADD_OWNERID_INDEX].Fid,
  10194. &RecordOwnerId,
  10195. NAM_ADD_OWNERID_SIZE,
  10196. &ActFldLen,
  10197. 0,
  10198. NULL
  10199. ));
  10200. if ((pWinsAdd != NULL) && (RecordOwnerId != OwnerId))
  10201. {
  10202. //
  10203. // We have exhausted all records for the owner. Break out
  10204. // of the loop
  10205. //
  10206. continue;
  10207. }
  10208. else
  10209. {
  10210. if (RecordOwnerId == OWNER_ID_OF_SPEC_REC)
  10211. {
  10212. continue;
  10213. }
  10214. }
  10215. pRspBuf->OwnerId = RecordOwnerId;
  10216. //
  10217. // Retrieve the version number
  10218. //
  10219. CALL_M( JetRetrieveColumn(
  10220. SesId,
  10221. TblId,
  10222. sNamAddTblRow[NAM_ADD_VERSIONNO_INDEX].Fid,
  10223. &(pRspBuf->VersNo),
  10224. sizeof(VERS_NO_T),
  10225. &ActFldLen,
  10226. 0,
  10227. NULL
  10228. )
  10229. );
  10230. //
  10231. // retrieve the name
  10232. //
  10233. CALL_M( JetRetrieveColumn(
  10234. SesId,
  10235. TblId,
  10236. sNamAddTblRow[NAM_ADD_NAME_INDEX].Fid,
  10237. Name,
  10238. NMSDB_MAX_NAM_LEN,
  10239. &(pRspBuf->NameLen),
  10240. 0,
  10241. NULL
  10242. )
  10243. );
  10244. //
  10245. // if name length is > 255, jet is returning an invalid value.
  10246. // Make the length equal to the max. length we can have for
  10247. // a netbios name. Also, log an event
  10248. //
  10249. if (pRspBuf->NameLen > WINS_MAX_NAME_SZ)
  10250. {
  10251. WINSEVT_LOG_M(pRspBuf->NameLen, WINS_EVT_NAME_TOO_LONG);
  10252. DBGPRINT1(ERR, "NmsDbGetDataRecsByName: Name length is too long = (%x)\n", pRspBuf->NameLen);
  10253. pRspBuf->NameLen = WINS_MAX_NS_NETBIOS_NAME_LEN;
  10254. }
  10255. //
  10256. // This macro will allocate memory for the name
  10257. //
  10258. NMSDB_STORE_NAME_M(pTls, pRspBuf, Name, pRspBuf->NameLen);
  10259. //
  10260. // Adjust the size to be passed to the push thread
  10261. //
  10262. *pRspBuffLen += pRspBuf->NameLen;
  10263. //
  10264. // Retrieve the flags byte
  10265. //
  10266. CALL_M( JetRetrieveColumn(
  10267. SesId,
  10268. TblId,
  10269. sNamAddTblRow[NAM_ADD_FLAGS_INDEX].Fid,
  10270. &(pRspBuf->Flag),
  10271. sizeof(pRspBuf->Flag),
  10272. &ActFldLen,
  10273. 0,
  10274. NULL
  10275. )
  10276. );
  10277. //
  10278. // if we were asked to retrieve only static records and
  10279. // this record is not a static record, skip it.
  10280. //
  10281. if ((TypeOfRecs & WINSINTF_STATIC) && !NMSDB_IS_ENTRY_STATIC_M(pRspBuf->Flag))
  10282. {
  10283. // DBGPRINT0(DET, "NmsDbGetDataRecs: Encountered a dynamic record but were asked to retrieve only static records\n");
  10284. continue;
  10285. }
  10286. if ((TypeOfRecs & WINSINTF_DYNAMIC) && NMSDB_IS_ENTRY_STATIC_M(pRspBuf->Flag))
  10287. {
  10288. // DBGPRINT0(DET, "NmsDbGetDataRecs: Encountered a static record but were asked to retrieve only dynamic records\n");
  10289. continue;
  10290. }
  10291. EntTyp = (BYTE)((pRspBuf->Flag & NMSDB_BIT_ENT_TYP));
  10292. if (
  10293. (EntTyp == NMSDB_UNIQUE_ENTRY)
  10294. ||
  10295. (EntTyp == NMSDB_NORM_GRP_ENTRY)
  10296. )
  10297. {
  10298. /* It is a unique entry*/
  10299. pRspBuf->fGrp = (EntTyp == NMSDB_UNIQUE_ENTRY) ?
  10300. FALSE : TRUE;
  10301. CALL_M( JetRetrieveColumn(
  10302. SesId,
  10303. TblId,
  10304. sNamAddTblRow[NAM_ADD_ADDRESS_INDEX].Fid,
  10305. &pRspBuf->NodeAdd,
  10306. sizeof(COMM_ADD_T),
  10307. &ActFldLen,
  10308. 0,
  10309. NULL
  10310. )
  10311. );
  10312. }
  10313. else // it is a special group or a multihomed entry
  10314. {
  10315. //
  10316. // Even if the entry is a multihomed entry, we set the
  10317. // fGrp flag to TRUE so that the formatting function
  10318. // works properly (called by PUSH thread). The EntTyp
  10319. // will be used to decipher whether it is a multihomned
  10320. // entry or not
  10321. //
  10322. FUTURES("Remove this hacky mechanism")
  10323. pRspBuf->fGrp =
  10324. (EntTyp == NMSDB_SPEC_GRP_ENTRY) ? TRUE : FALSE;
  10325. /*
  10326. * get member addresses.
  10327. *
  10328. * This function is only called on RPC thread. We want to get
  10329. * the members, even if they are expired. We can do that by
  10330. * passing a TRUE value for the STATIC flag parameter.
  10331. * NmsDbGetDataRecsByName is the only way to get all the members
  10332. * including the expired ones.
  10333. */
  10334. StoreGrpMems(
  10335. pTls,
  10336. WINS_E_WINSRPC,
  10337. pRspBuf->pName,
  10338. 0, //not accessed by StoreGrpMems if Client_e
  10339. //is not WINS_E_NMSSCV
  10340. SesId,
  10341. TblId,
  10342. TRUE, // NMSDB_IS_ENTRY_STATIC_M(pRspBuf->Flag),
  10343. (PRPL_REC_ENTRY_T)pRspBuf
  10344. );
  10345. if (
  10346. (pRspBuf->NoOfAdds == 0)
  10347. &&
  10348. (NMSDB_ENTRY_ACT_M(pRspBuf->Flag))
  10349. )
  10350. {
  10351. //
  10352. //change the state to released so that the
  10353. //record shows up as released when displayed
  10354. //
  10355. NMSDB_CLR_STATE_M(pRspBuf->Flag);
  10356. NMSDB_SET_STATE_M(pRspBuf->Flag, NMSDB_E_RELEASED);
  10357. }
  10358. *pRspBuffLen +=
  10359. (pRspBuf->NoOfAdds * sizeof(COMM_ADD_T) * 2);
  10360. }
  10361. //
  10362. // get the timestamp field
  10363. //
  10364. CALL_M( JetRetrieveColumn(
  10365. SesId,
  10366. TblId,
  10367. sNamAddTblRow[NAM_ADD_TIMESTAMP_INDEX].Fid,
  10368. &(pRspBuf->TimeStamp),
  10369. sizeof(pRspBuf->TimeStamp),
  10370. &ActFldLen,
  10371. 0,
  10372. NULL
  10373. )
  10374. );
  10375. if (NMSDB_IS_ENTRY_STATIC_M(pRspBuf->Flag) &&
  10376. (RecordOwnerId == NMSDB_LOCAL_OWNER_ID) &&
  10377. NMSDB_ENTRY_ACT_M(pRspBuf->Flag))
  10378. {
  10379. pRspBuf->TimeStamp = MAXLONG;
  10380. }
  10381. //
  10382. // increment the counter and the pointer to past the last record.
  10383. //
  10384. pRspBuf = (PRPL_REC_ENTRY2_T)((LPBYTE)pRspBuf + RPL_REC_ENTRY2_SIZE);
  10385. (*pNoOfRecsRet)++;
  10386. //
  10387. // if we have retrieved the max. number asked for, break out of
  10388. // the loop
  10389. //
  10390. if (*pNoOfRecsRet == NoOfRecsDesired)
  10391. {
  10392. break;
  10393. }
  10394. //
  10395. // decrease the granularity of [BeginTransaction()..CommitTransaction()] intervals
  10396. //
  10397. if (*pNoOfRecsRet/CommitCnt >= MAX_RECS_BEFORE_COMMIT)
  10398. {
  10399. CALL_M(JetCommitTransaction(SesId, JET_bitCommitFlush));
  10400. fTransCommitted = TRUE;
  10401. CommitCnt++;
  10402. CALL_M(JetBeginTransaction(SesId));
  10403. fTransCommitted = FALSE;
  10404. }
  10405. } while(JetMove(SesId, TblId, MoveDir/*JET_MoveNext*/, 0) >= 0);
  10406. #ifdef WINSDBG
  10407. EndTime = GetTickCount();
  10408. DBGPRINT2(TM, "NmsDbGetDataRecs: Retrieved %d records in %d secs\n",
  10409. *pNoOfRecsRet, StartTime - EndTime);
  10410. #endif
  10411. } // if RetStat == WINS_SUCCESS
  10412. } // end of try {..}
  10413. finally {
  10414. if (AbnormalTermination())
  10415. {
  10416. DBGPRINT0(ERR,
  10417. "NmsDbGetDataRecsByName: Terminating abnormally\n");
  10418. WINSEVT_LOG_D_M(WINS_FAILURE, WINS_EVT_RPC_EXC);
  10419. RetStat = WINS_FAILURE;
  10420. }
  10421. DBGPRINT1(FLOW, "NmsDbGetDataRecsByName:Retrieved %d records\n",
  10422. *pNoOfRecsRet);
  10423. //
  10424. //
  10425. // We are done. Let us commit the transaction if it is not yet committed
  10426. //
  10427. if (!fTransCommitted)
  10428. {
  10429. JET_ERR JetRetStat;
  10430. JetRetStat = JetCommitTransaction(SesId, JET_bitCommitFlush);
  10431. if (RetStat != WINS_FAILURE)
  10432. #pragma prefast(disable:243, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  10433. #pragma prefast(suppress:241, Taken care of by the AbnormalTermination() test (PREfast bug 553))
  10434. CALL_M(JetRetStat);
  10435. #pragma prefast(enable:243, Why disable/enable? Prefast bug 709)
  10436. }
  10437. }
  10438. DBGLEAVE("NmsDbGetDataRecsByName\n");
  10439. return(RetStat);
  10440. }
  10441. STATUS
  10442. NmsDbEndTransaction(
  10443. VOID
  10444. )
  10445. /*++
  10446. Routine Description:
  10447. Arguments:
  10448. Externals Used:
  10449. None
  10450. Return Value:
  10451. Success status codes --
  10452. Error status codes --
  10453. Error Handling:
  10454. Called by:
  10455. WinsMscChkTermEvt
  10456. Side Effects:
  10457. Comments:
  10458. None
  10459. --*/
  10460. {
  10461. PWINSTHD_TLS_T pTls;
  10462. DBGENTER("NmsDbEndTransaction\n");
  10463. GET_TLS_M(pTls);
  10464. ASSERT(pTls != NULL);
  10465. CALL_M(
  10466. JetCommitTransaction(pTls->SesId, JET_bitCommitFlush)
  10467. );
  10468. DBGLEAVE("NmsDbEndTransaction\n");
  10469. return(WINS_SUCCESS);
  10470. }
  10471. #if DYNLOADJET
  10472. STATUS
  10473. SetForJet(
  10474. VOID
  10475. )
  10476. {
  10477. HMODULE DllHandle;
  10478. DWORD Error;
  10479. LPTSTR pDllName;
  10480. #ifdef WINS_INTERACTIVE
  10481. DynLoadJetVersion = getenv("JET500") ? DYN_LOAD_JET_500
  10482. : (getenv("JET200") ? DYN_LOAD_JET_200 : DYN_LOAD_JET_600);
  10483. #endif
  10484. DBGENTER("SetForJet\n");
  10485. if (DynLoadJetVersion == DYN_LOAD_JET_500)
  10486. {
  10487. pDllName = TEXT("jet500.dll");
  10488. NAM_ADD_OWNERID_SIZE = sizeof(DWORD);
  10489. BASENAME = "j50";
  10490. sNamAddTblRow[3].FldTyp = JET_coltypLong;
  10491. sOwnAddTblRow[0].FldTyp = JET_coltypLong;
  10492. }
  10493. else if (DynLoadJetVersion == DYN_LOAD_JET_600 ) {
  10494. // jet600.dll is now called esent.dll!
  10495. pDllName = TEXT("esent.dll");
  10496. NAM_ADD_OWNERID_SIZE = sizeof(DWORD);
  10497. BASENAME = "j50";
  10498. sNamAddTblRow[3].FldTyp = JET_coltypLong;
  10499. sOwnAddTblRow[0].FldTyp = JET_coltypLong;
  10500. }
  10501. else
  10502. {
  10503. pDllName = TEXT("jet.dll");
  10504. NAM_ADD_OWNERID_SIZE = sizeof(BYTE);
  10505. BASENAME = "jet";
  10506. sNamAddTblRow[3].FldTyp = JET_coltypUnsignedByte;
  10507. sOwnAddTblRow[0].FldTyp = JET_coltypUnsignedByte;
  10508. }
  10509. DBGPRINT2(ERR,"SetForJet: loading DLL %ws: version %ld\n", pDllName, DynLoadJetVersion);
  10510. OWN_ADD_OWNERID_SIZE = NAM_ADD_OWNERID_SIZE;
  10511. //
  10512. // Load the DLL that contains the service.
  10513. //
  10514. DllHandle = LoadLibrary( pDllName );
  10515. if ( DllHandle == NULL )
  10516. {
  10517. Error = GetLastError();
  10518. DBGPRINT2(ERR,"SetForJet: Failed to load DLL %ws: %ld\n", pDllName, Error);
  10519. return(WINS_FAILURE);
  10520. }
  10521. else
  10522. {
  10523. DWORD i;
  10524. for (i=0; i < NMSDB_SIZEOFJETFTBL; i++)
  10525. {
  10526. CHAR chFnName[64];
  10527. LPSTR pAt;
  10528. LPSTR pFnName;
  10529. pFnName = (LPSTR)NmsDbJetFTbl[i].pFName;
  10530. #if _X86_
  10531. if ( DynLoadJetVersion != DYN_LOAD_JET_200) {
  10532. strcpy(chFnName,NmsDbJetFTbl[i].pFName);
  10533. pAt = strrchr(chFnName,'@');
  10534. if (pAt != NULL)
  10535. {
  10536. *pAt = '\0';
  10537. pFnName = chFnName;
  10538. }
  10539. }
  10540. #endif
  10541. if ((NmsDbJetFTbl[i].pFAdd = (JETPROC)GetProcAddress(DllHandle,
  10542. (DynLoadJetVersion >= DYN_LOAD_JET_500) ? pFnName : ULongToPtr(NmsDbJetFTbl[i].FIndex))) == NULL)
  10543. {
  10544. DBGPRINT2(ERR, "SetForJet: Failed to get address of function %s: %ld\n", NmsDbJetFTbl[i].pFName, GetLastError());
  10545. return(WINS_FAILURE);
  10546. }
  10547. else
  10548. {
  10549. DBGPRINT3(DET, "SetForJet: Got address of function %s (%d): %p\n", NmsDbJetFTbl[i].pFName, i, NmsDbJetFTbl[i].pFAdd);
  10550. }
  10551. }
  10552. }
  10553. return(WINS_SUCCESS);
  10554. }
  10555. #endif
  10556. //
  10557. // Name of the process that converts jet200 db to jet500 db format
  10558. //
  10559. CHECK("Unicode from results in an exception from CreateProcess")
  10560. //#define JETCONVDB TEXT("jetconv WINS /@")
  10561. VOID
  10562. RecoverJetDb(
  10563. DYN_LOAD_JET_VERSION JetVersion
  10564. )
  10565. /*++
  10566. This routine recovers the database by calling JetInit/JetTerm on
  10567. the database.
  10568. Argument:
  10569. JetVersion - The version of the jet to use when recovering the db.
  10570. --*/
  10571. {
  10572. DYN_LOAD_JET_VERSION JetVersionSv = DynLoadJetVersion;
  10573. ASSERT(DYN_LOAD_JET_500 <= JetVersion );
  10574. //
  10575. // First JetTerm the current jet engine.
  10576. //
  10577. NmsDbRelRes();
  10578. //
  10579. // now load the appropriate version jet dll.
  10580. //
  10581. DynLoadJetVersion = JetVersion;
  10582. SetForJet();
  10583. //
  10584. // set system params and jetinit.
  10585. //
  10586. SetSystemParams(TRUE);
  10587. JetInit(&sJetInstance);
  10588. //
  10589. // finally, JetTerm this jet dll.
  10590. //
  10591. NmsDbRelRes();
  10592. DynLoadJetVersion = JetVersionSv;
  10593. return;
  10594. }
  10595. #define JETCONVDB200 "jetconv WINS /200 /@"
  10596. #define JETCONVDB500 "jetconv WINS /500 /@"
  10597. STATUS
  10598. ConvertJetDb(
  10599. JET_ERR JetRetStat
  10600. )
  10601. {
  10602. BOOL RetVal;
  10603. PROCESS_INFORMATION ProcInfo = {0};
  10604. STARTUPINFOA StartInfo = {0};
  10605. LPSTR pArg;
  10606. DBGPRINT1(DET, "ConvertJetDb: Converting %s\n", (JetRetStat == JET_errDatabase200Format)
  10607. ? JETCONVDB200 : JETCONVDB500);
  10608. if (JetRetStat == JET_errDatabase200Format)
  10609. {
  10610. fDbIs200 = TRUE;
  10611. if (DynLoadJetVersion == DYN_LOAD_JET_500)
  10612. {
  10613. //
  10614. // Can not run jet200 using jet500.dll on NT5.0
  10615. //
  10616. DBGPRINT0(ERR, "Can not run jet200 using jet500.dll on NT5.0\n");
  10617. return WINS_FAILURE;
  10618. } else if (DynLoadJetVersion == DYN_LOAD_JET_600){
  10619. pArg = JETCONVDB200;
  10620. } else {
  10621. ASSERT(FALSE);
  10622. return WINS_FAILURE;
  10623. }
  10624. } else if ( JetRetStat == JET_errDatabase500Format ) {
  10625. if (DynLoadJetVersion == DYN_LOAD_JET_600)
  10626. {
  10627. // before we start the conversion, we need to bring the db to
  10628. // consistent state. The 351 to 4.0 conversion tool (upg351db.exe)
  10629. // did this from within the tool but the 4.0 to 5.0 tool
  10630. // does not do this from within the tool so we need to do it here.
  10631. RecoverJetDb( DYN_LOAD_JET_500 );
  10632. // Start the convert process
  10633. //
  10634. pArg = JETCONVDB500;
  10635. fDbIs500 = TRUE;
  10636. } else {
  10637. ASSERT(FALSE);
  10638. return WINS_FAILURE;
  10639. }
  10640. }
  10641. //return WINS_FAILURE;
  10642. StartInfo.cb = sizeof(StartInfo);
  10643. //
  10644. // Create the convert process to do the conversion. This process
  10645. //
  10646. DBGPRINT0(DET, "ConvertJetDb - creating convert process\n");
  10647. RetVal = CreateProcessA(
  10648. NULL, //
  10649. pArg,
  10650. NULL, //default proc. sec.
  10651. NULL, //default thread. sec.
  10652. FALSE, //don't inherit handles
  10653. DETACHED_PROCESS, //no creation flags
  10654. NULL, //default env.
  10655. NULL, //current drv/dir. same as creator
  10656. &StartInfo, //no startup info
  10657. &ProcInfo //no process info.
  10658. );
  10659. if (!RetVal)
  10660. {
  10661. DBGPRINT1(ERR, "ConvertJetDb: Create process failed with error (%x)\n", GetLastError());
  10662. return(WINS_FAILURE);
  10663. }
  10664. fConvJetDbCalled = TRUE;
  10665. // if CreateProcess was successful, clean out handles passed to WINS
  10666. CloseHandle(ProcInfo.hProcess);
  10667. CloseHandle(ProcInfo.hThread);
  10668. //
  10669. // Log an event.
  10670. //
  10671. DBGPRINT0(DET, "ConvertJetDb - returning\n");
  10672. // WINSEVT_LOG_M(WINS_SUCCESS, WINS_EVT_TEMP_TERM_UNTIL_CONV);
  10673. return(WINS_SUCCESS);
  10674. }