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

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