PageRenderTime 58ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/condor-7.9.0/src/classad_support/collectionClient.cpp

#
C++ | 1177 lines | 858 code | 219 blank | 100 comment | 179 complexity | e7586ab7c5928fcdd32bd61c280dc284 MD5 | raw file
Possible License(s): Apache-2.0
  1. /***************************************************************
  2. *
  3. * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
  4. * University of Wisconsin-Madison, WI.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License"); you
  7. * may not use this file except in compliance with the License. You may
  8. * obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. ***************************************************************/
  19. #include "condor_common.h"
  20. #include "condor_io.h"
  21. #include "classad/common.h"
  22. #include "collectionClient.h"
  23. #include "classad/transaction.h"
  24. using namespace std;
  25. namespace classad {
  26. ClassAdCollectionClient::
  27. ClassAdCollectionClient( )
  28. {
  29. log_fp = NULL;
  30. }
  31. ClassAdCollectionClient::
  32. ~ClassAdCollectionClient( )
  33. {
  34. if( serverSock ) {
  35. delete serverSock;
  36. }
  37. if( log_fp ) {
  38. fclose( log_fp );
  39. }
  40. }
  41. bool ClassAdCollectionClient::
  42. InitializeFromLog( const string &filename )
  43. {
  44. // clear out transaction table
  45. Disconnect( );
  46. // load new state
  47. logFileName = filename;
  48. if( !filename.empty( ) ) {
  49. if( !ReadLogFile( ) ) {
  50. CondorErrMsg += "; could not initialize from file " + filename;
  51. return( false );
  52. }
  53. }
  54. return( true );
  55. }
  56. void ClassAdCollectionClient::
  57. Recover( int &committed, int &aborted, int &unknown )
  58. {
  59. LocalXactionTable::iterator itr;
  60. ClientTransaction *xaction;
  61. int outcome;
  62. committed = aborted = unknown = 0;
  63. // attempt to commit all pending transactions
  64. for( itr=localXactionTable.begin( ); itr!=localXactionTable.end(); itr++) {
  65. xaction = itr->second;
  66. if( xaction->GetXactionState( )!=ClientTransaction::PENDING ) continue;
  67. CloseTransaction( itr->first, true, outcome );
  68. switch( outcome ) {
  69. case XACTION_COMMITTED: committed++;break;
  70. case XACTION_ABORTED: aborted++; break;
  71. case XACTION_UNKNOWN: unknown++; break;
  72. }
  73. }
  74. }
  75. bool ClassAdCollectionClient::
  76. OperateInRecoveryMode( ClassAd *rec )
  77. {
  78. int opType=-1;
  79. rec->EvaluateAttrInt( ATTR_OP_TYPE, opType );
  80. switch( opType ) {
  81. case ClassAdCollOp_CommitTransaction: {
  82. ClientTransaction *xaction;
  83. string xactionName, serverAddr;
  84. int serverPort;
  85. // obtain transaction state
  86. rec->EvaluateAttrString( ATTR_XACTION_NAME, xactionName );
  87. rec->EvaluateAttrString( "ServerAddr", serverAddr );
  88. rec->EvaluateAttrInt( "ServerPort", serverPort );
  89. if( !(xaction = new ClientTransaction ) ) {
  90. CondorErrno = ERR_MEM_ALLOC_FAILED;
  91. CondorErrMsg = "";
  92. return( false );
  93. }
  94. // restore transaction state
  95. xaction->SetXactionName( xactionName );
  96. xaction->SetXactionState( ClientTransaction::PENDING );
  97. xaction->SetServerAddr( serverAddr, serverPort );
  98. // enter into transaction table
  99. localXactionTable[xactionName] = xaction;
  100. return( true );
  101. }
  102. // ack commit and abort have the same action
  103. case ClassAdCollOp_AckCommitTransaction:
  104. case ClassAdCollOp_AbortTransaction: {
  105. ClientTransaction *xaction;
  106. string xactionName;
  107. LocalXactionTable::iterator itr;
  108. rec->EvaluateAttrString( ATTR_XACTION_NAME, xactionName );
  109. if( ( itr=localXactionTable.find( xactionName ) ) ==
  110. localXactionTable.end( ) ) {
  111. CondorErrno = ERR_NO_SUCH_TRANSACTION;
  112. CondorErrMsg = "transaction "+xactionName+" doesn't exist";
  113. return( false );
  114. }
  115. xaction = itr->second;
  116. delete xaction;
  117. localXactionTable.erase( itr );
  118. return( true );
  119. }
  120. default:
  121. break;
  122. }
  123. return( false );
  124. }
  125. bool ClassAdCollectionClient::
  126. Connect( const string &addr, int port, bool useTCP )
  127. {
  128. // we allow only one connection at a time
  129. if( serverSock && !Disconnect( ) ) return( false );
  130. // create a socket ...
  131. if( !( serverSock = useTCP ? (Sock *)new ReliSock( ) : (Sock *)new SafeSock ) ) {
  132. CondorErrno = ERR_MEM_ALLOC_FAILED;
  133. CondorErrMsg = "";
  134. return( false );
  135. }
  136. // connect ...
  137. if( !serverSock->connect( (char*) addr.c_str( ), port ) ) {
  138. CondorErrno = ERR_CONNECT_FAILED;
  139. CondorErrMsg = "failed to connect to server" + addr;
  140. delete serverSock;
  141. serverSock = NULL;
  142. return( false );
  143. }
  144. // if using TCP, send a "connect" command
  145. serverSock->encode( );
  146. if( useTCP && ( !serverSock->put( int(ClassAdCollOp_Connect) ) ||
  147. !serverSock->end_of_message( ) ) ) {
  148. CondorErrno = ERR_COMMUNICATION_ERROR;
  149. CondorErrMsg = "failed to send connect request to server";
  150. delete serverSock;
  151. serverSock = NULL;
  152. return( false );
  153. }
  154. // done
  155. serverAddr = addr;
  156. serverPort = port;
  157. return( true );
  158. }
  159. bool ClassAdCollectionClient::
  160. Disconnect( )
  161. {
  162. int outcome;
  163. // already disconnected?
  164. if( !serverSock ) return( true );
  165. // abort all active transactions
  166. LocalXactionTable::iterator itr;
  167. ClientTransaction *xaction;
  168. string xactionName;
  169. bool rval = true;
  170. for( itr=localXactionTable.begin(); itr!=localXactionTable.end(); itr++) {
  171. xaction = itr->second;
  172. if( xaction && xaction->GetXactionState( )==ClientTransaction::ACTIVE ){
  173. xaction->GetXactionName( xactionName );
  174. rval = rval && CloseTransaction( xactionName, false, outcome );
  175. delete xaction;
  176. localXactionTable.erase( xactionName );
  177. }
  178. }
  179. // disconnect from server (send command only if TCP)
  180. if( serverSock->type( ) == Stream::reli_sock ) {
  181. serverSock->encode( );
  182. serverSock->put( (int)ClassAdCollOp_Disconnect );
  183. serverSock->end_of_message( );
  184. serverSock->close( );
  185. }
  186. delete serverSock;
  187. serverSock = NULL;
  188. currentXactionName = "";
  189. return( rval );
  190. }
  191. bool ClassAdCollectionClient::
  192. OpenTransaction( const string &transactionName )
  193. {
  194. ClientTransaction *xaction;
  195. // check if we are bound to a server
  196. if( !serverSock ) {
  197. CondorErrno = ERR_CLIENT_NOT_CONNECTED;
  198. CondorErrMsg = "client not bound to server";
  199. return( false );
  200. }
  201. if( serverSock->type( ) != Stream::reli_sock ) {
  202. CondorErrno = ERR_BAD_CONNECTION_TYPE;
  203. CondorErrMsg = "cannot open transaction over unreliable connection";
  204. return( false );
  205. }
  206. // check if the transaction name is being used locally
  207. if( localXactionTable.find( transactionName ) != localXactionTable.end( ) ){
  208. CondorErrno = ERR_TRANSACTION_EXISTS;
  209. CondorErrMsg = "transaction " + transactionName + " already exists";
  210. return( false );
  211. }
  212. // records for open transaction and ack from server
  213. ClassAd rec, *ack=NULL;
  214. rec.InsertAttr( ATTR_XACTION_NAME, transactionName );
  215. rec.InsertAttr( ATTR_OP_TYPE, ClassAdCollOp_OpenTransaction );
  216. // send the record to the server
  217. if( !SendOpToServer( ClassAdCollOp_OpenTransaction, &rec,
  218. ClassAdCollOp_AckOpenTransaction, ack ) ) {
  219. if( ack ) delete ack;
  220. return( false );
  221. }
  222. // create a client transaction object and enter into local table
  223. delete ack;
  224. if( !( xaction = new ClientTransaction( ) ) ) {
  225. CondorErrno = ERR_MEM_ALLOC_FAILED;
  226. CondorErrMsg = "";
  227. return( false );
  228. }
  229. xaction->SetXactionName( transactionName );
  230. xaction->SetServerAddr( serverAddr, serverPort );
  231. localXactionTable[transactionName] = xaction;
  232. // use new transaction as current transaction
  233. currentXactionName = transactionName;
  234. return( true );
  235. }
  236. bool ClassAdCollectionClient::
  237. DoCommitProtocol( const string &xactionName, int &outcome,
  238. ClientTransaction *xaction )
  239. {
  240. ClassAd rec, *ack;
  241. int xactionState = xaction->GetXactionState( );
  242. int op = ClassAdCollOp_CommitTransaction;
  243. int ackOp = ClassAdCollOp_AckCommitTransaction;
  244. rec.InsertAttr( ATTR_XACTION_NAME, xactionName );
  245. rec.InsertAttr( ATTR_OP_TYPE, op );
  246. // log only if the transaction is active (i.e., no commit rec in log)
  247. if( xactionState == ClientTransaction::ACTIVE && log_fp &&
  248. !xaction->LogCommit( log_fp, &unparser ) ) {
  249. CondorErrMsg += "; FATAL ERROR: failed to log commit record";
  250. return( false );
  251. }
  252. xaction->SetXactionState( ClientTransaction::PENDING );
  253. // send operation to server and get ack
  254. if( !SendOpToServer( op, &rec, ackOp, ack ) ) {
  255. outcome = XACTION_UNKNOWN;
  256. CondorErrMsg += "; failed to close transaction";
  257. return( false );
  258. }
  259. // check if there was a server error (xaction was aborted)
  260. if( CondorErrno != ERR_OK ) {
  261. if( log_fp ) xaction->LogAbort( log_fp, &unparser );
  262. delete xaction;
  263. localXactionTable.erase( xactionName );
  264. outcome = XACTION_ABORTED;
  265. if( currentXactionName == xactionName ) currentXactionName = "";
  266. return( false );
  267. }
  268. // write the ack record to the log file
  269. if( !WriteLogEntry( log_fp, ack, true ) ) {
  270. outcome = XACTION_UNKNOWN;
  271. delete ack;
  272. return( false );
  273. }
  274. // send the "forget transaction" command to the server
  275. // (even if we can't send this message, we know the xaction was
  276. // committed --- the server will forget the xaction in its own time)
  277. delete ack;
  278. ack = NULL;
  279. outcome = XACTION_COMMITTED;
  280. op = ClassAdCollOp_ForgetTransaction;
  281. rec.InsertAttr( ATTR_OP_TYPE, op );
  282. if( currentXactionName == xactionName ) currentXactionName = "";
  283. SendOpToServer( op, &rec, ackOp, ack ); // won't get an ack for this
  284. // done
  285. delete xaction;
  286. localXactionTable.erase( xactionName );
  287. return( true );
  288. }
  289. bool ClassAdCollectionClient::
  290. CloseTransaction( const string &xactionName, bool commit, int &outcome )
  291. {
  292. outcome = XACTION_UNKNOWN;
  293. // check if the transaction exists
  294. LocalXactionTable::iterator itr = localXactionTable.find( xactionName );
  295. if( itr == localXactionTable.end( ) ){
  296. CondorErrno = ERR_NO_SUCH_TRANSACTION;
  297. CondorErrMsg = "transaction " + xactionName + " doesn't exist";
  298. return( false );
  299. }
  300. ClientTransaction *xaction = itr->second;
  301. // make sure we're connected to the right server
  302. string xactionServerAddr;
  303. int xactionServerPort;
  304. Sock *savedSock;
  305. string savedServerAddr;
  306. int savedServerPort;
  307. bool rval=false;
  308. xaction->GetServerAddr( xactionServerAddr, xactionServerPort );
  309. // "save" current connection
  310. savedSock = serverSock;
  311. savedServerAddr = serverAddr;
  312. savedServerPort = serverPort;
  313. if( xactionServerAddr != serverAddr || xactionServerPort != serverPort ) {
  314. if( !( serverSock = new ReliSock( ) ) ||
  315. !serverSock->connect( (char*)xactionServerAddr.c_str(),
  316. xactionServerPort ) ) {
  317. CondorErrno = ERR_COMMUNICATION_ERROR;
  318. CondorErrMsg = "failed to connect to server " + xactionServerAddr;
  319. if( serverSock ) delete serverSock;
  320. serverSock = savedSock;
  321. return( false );
  322. }
  323. serverAddr = xactionServerAddr;
  324. serverPort = xactionServerPort;
  325. }
  326. // check if we can talk to the server
  327. if( !serverSock ) {
  328. CondorErrno = ERR_CLIENT_NOT_CONNECTED;
  329. CondorErrMsg = "client not bound to server";
  330. if( serverSock != savedSock ) {
  331. delete serverSock;
  332. serverSock = savedSock;;
  333. serverAddr = savedServerAddr;
  334. serverPort = savedServerPort;
  335. }
  336. return( false );
  337. }
  338. if( serverSock->type( ) != Stream::reli_sock ) {
  339. CondorErrno = ERR_BAD_CONNECTION_TYPE;
  340. CondorErrMsg = "cannot close transaction over unreliable connection";
  341. if( serverSock != savedSock ) {
  342. delete serverSock;
  343. serverSock = savedSock;;
  344. serverAddr = savedServerAddr;
  345. serverPort = savedServerPort;
  346. }
  347. return( false );
  348. }
  349. // get the local transaction state
  350. int xactionState = xaction->GetXactionState( );
  351. if( xactionState == ClientTransaction::ACTIVE ) {
  352. if( commit ) {
  353. // if committing, do the commit protocol
  354. rval = DoCommitProtocol( xactionName, outcome, xaction );
  355. } else {
  356. // aborting the transaction
  357. ClassAd rec, *ack=NULL;
  358. int op, ackOp;
  359. op = ClassAdCollOp_AbortTransaction;
  360. rec.InsertAttr( ATTR_XACTION_NAME, xactionName );
  361. rec.InsertAttr( ATTR_OP_TYPE, op );
  362. // ok if there's an error here --- server will clean up
  363. SendOpToServer( op, &rec, ackOp, ack ); // wont get an ack
  364. delete xaction;
  365. localXactionTable.erase( xactionName );
  366. // restore connection
  367. serverSock = savedSock;
  368. serverAddr = savedServerAddr;
  369. serverPort = savedServerPort;
  370. rval = true;
  371. }
  372. } else if( xactionState == ClientTransaction::PENDING ) {
  373. ClassAd rec, *ack=NULL;
  374. int op, ackOp;
  375. int serverXactionState;
  376. // pending: may be absent, active or committed in server
  377. outcome = XACTION_UNKNOWN;
  378. if( !GetServerXactionState( xactionName, serverXactionState ) ) {
  379. rval = false;
  380. } else {
  381. switch( serverXactionState ) {
  382. // if the server doesn't have this transaction abort
  383. case ServerTransaction::ABSENT: {
  384. outcome = XACTION_ABORTED;
  385. delete xaction;
  386. localXactionTable.erase( xactionName );
  387. // return false if we wanted to commit
  388. rval = !commit;
  389. break;
  390. }
  391. // if the server already committed, just send the forget
  392. case ServerTransaction::COMMITTED: {
  393. op = ClassAdCollOp_ForgetTransaction;
  394. rec.InsertAttr( ATTR_XACTION_NAME, xactionName );
  395. rec.InsertAttr( ATTR_OP_TYPE, op );
  396. // ok if error here --- server will clean up
  397. SendOpToServer( op, &rec, ackOp, ack ); // wont get an ack
  398. outcome = XACTION_COMMITTED;
  399. delete xaction;
  400. localXactionTable.erase( xactionName );
  401. // return true if we wanted to commit
  402. rval = commit;
  403. break;
  404. }
  405. // if xaction is active in server
  406. case ServerTransaction::ACTIVE: {
  407. if( commit ) {
  408. // do the commit protocol
  409. rval=DoCommitProtocol( xactionName, outcome, xaction );
  410. } else {
  411. op = ClassAdCollOp_AbortTransaction;
  412. rec.InsertAttr( ATTR_XACTION_NAME, xactionName );
  413. rec.InsertAttr( ATTR_OP_TYPE, op );
  414. // ok if error here --- server will clean up
  415. SendOpToServer( op, &rec, ackOp, ack ); // wont get ack
  416. delete xaction;
  417. localXactionTable.erase( xactionName );
  418. outcome = XACTION_ABORTED;
  419. rval = true;
  420. break;
  421. }
  422. }
  423. default:
  424. rval = false;
  425. break;
  426. }
  427. }
  428. }
  429. // restore connection if necessary
  430. if( serverSock != savedSock ) {
  431. delete serverSock;
  432. serverSock = savedSock;
  433. serverAddr = savedServerAddr;
  434. serverPort = savedServerPort;
  435. }
  436. // return return value
  437. return( rval );
  438. }
  439. bool ClassAdCollectionClient::
  440. CreateSubView( const ViewName &viewName, const ViewName &parentViewName,
  441. const string &constraint, const string &rank, const string &partitionExprs )
  442. {
  443. ClassAd *rec, *ack;
  444. bool rval;
  445. // create the op record
  446. rec=_CreateSubView(viewName,parentViewName,constraint,rank,partitionExprs);
  447. if( !rec ) return( false );
  448. // perform the operation on the server
  449. rval = SendOpToServer( ClassAdCollOp_CreateSubView, rec,
  450. ClassAdCollOp_AckViewOp, ack );
  451. if( rec ) delete rec;
  452. if( ack ) delete ack;
  453. return( rval );
  454. }
  455. bool ClassAdCollectionClient::
  456. CreatePartition( const ViewName &viewName, const ViewName &parentViewName,
  457. const string &constraint, const string &rank, const string &partitionExprs,
  458. ClassAd *rep )
  459. {
  460. ClassAd *rec, *ack;
  461. bool rval;
  462. // create the op record
  463. rec = _CreatePartition( viewName, parentViewName, constraint, rank,
  464. partitionExprs, rep );
  465. if( !rec ) return( false );
  466. // perform the operation on the server
  467. rval = SendOpToServer( ClassAdCollOp_CreatePartition, rec,
  468. ClassAdCollOp_AckViewOp, ack );
  469. if( rec ) delete rec;
  470. if( ack ) delete ack;
  471. return( rval );
  472. }
  473. bool ClassAdCollectionClient::
  474. DeleteView( const ViewName &viewName )
  475. {
  476. ClassAd *rec, *ack;
  477. bool rval;
  478. // create the op record
  479. if( !( rec = _DeleteView( viewName ) ) ) {
  480. return( false );
  481. }
  482. // perform operation on server
  483. rval = SendOpToServer( ClassAdCollOp_DeleteView, rec,
  484. ClassAdCollOp_AckViewOp, ack );
  485. if( rec ) delete rec;
  486. if( ack ) delete ack;
  487. return( rval );
  488. }
  489. bool ClassAdCollectionClient::
  490. SetViewInfo( const ViewName &viewName, const string &constraint,
  491. const string &rank, const string &partitionExprs )
  492. {
  493. ClassAd *rec, *ack;
  494. bool rval;
  495. // create the op record
  496. if( !( rec=_SetViewInfo( viewName, constraint, rank, partitionExprs ) ) ) {
  497. return( false );
  498. }
  499. // perform operation on server
  500. rval = SendOpToServer( ClassAdCollOp_SetViewInfo, rec,
  501. ClassAdCollOp_AckViewOp, ack );
  502. if( rec ) delete rec;
  503. if( ack ) delete ack;
  504. return( rval );
  505. }
  506. bool ClassAdCollectionClient::
  507. _GetViewNames( int command, const ViewName &view, vector<string>& viewNames)
  508. {
  509. ClassAd rec, *ack=NULL;
  510. Value val;
  511. ExprList *el;
  512. ExprListIterator itr;
  513. string strVal;
  514. viewNames.clear( );
  515. rec.InsertAttr( ATTR_OP_TYPE, command );
  516. rec.InsertAttr( ATTR_VIEW_NAME, view );
  517. if( !SendOpToServer( command, &rec, ClassAdCollOp_AckReadOp, ack ) ||
  518. CondorErrno != ERR_OK ) {
  519. if( ack ) delete ack;
  520. return( false );
  521. }
  522. if( !ack->EvaluateAttr( command==ClassAdCollOp_GetPartitionedViewNames ?
  523. ATTR_PARTITIONED_VIEWS:ATTR_SUBORDINATE_VIEWS, val ) ||
  524. !val.IsListValue( el ) ) {
  525. CondorErrno = ERR_BAD_SERVER_ACK;
  526. CondorErrMsg = "bad server ack --- bad or missing view names";
  527. return( false );
  528. }
  529. itr.Initialize( el );
  530. while( !itr.IsAfterLast( ) ) {
  531. if( !itr.CurrentValue( val ) || !val.IsStringValue( strVal ) ) {
  532. delete ack;
  533. viewNames.clear( );
  534. return( false );
  535. }
  536. viewNames.push_back( strVal );
  537. itr.NextExpr( );
  538. }
  539. return( true );
  540. }
  541. bool ClassAdCollectionClient::
  542. GetSubordinateViewNames( const ViewName &view, vector<string>& viewNames)
  543. {
  544. return(_GetViewNames(ClassAdCollOp_GetSubordinateViewNames,view,viewNames));
  545. }
  546. bool ClassAdCollectionClient::
  547. GetPartitionedViewNames( const ViewName &view, vector<string>& viewNames)
  548. {
  549. return(_GetViewNames(ClassAdCollOp_GetPartitionedViewNames,view,viewNames));
  550. }
  551. bool ClassAdCollectionClient::
  552. FindPartitionName( const ViewName &view, ClassAd *rep, ViewName &parViewName)
  553. {
  554. ClassAd rec, *ack=NULL;
  555. rec.InsertAttr( ATTR_OP_TYPE, ClassAdCollOp_FindPartitionName );
  556. rec.InsertAttr( ATTR_VIEW_NAME, view );
  557. rec.Insert( ATTR_AD, rep );
  558. if( !SendOpToServer( ClassAdCollOp_FindPartitionName, &rec,
  559. ClassAdCollOp_AckReadOp, ack ) || CondorErrno != ERR_OK ) {
  560. rec.Remove( ATTR_AD );
  561. if( ack ) delete ack;
  562. parViewName = "";
  563. return( false );
  564. }
  565. rec.Remove( ATTR_AD );
  566. if( !ack->EvaluateAttrString( "PartitionName", parViewName ) ) {
  567. CondorErrno = ERR_BAD_SERVER_ACK;
  568. CondorErrMsg = "bad server ack --- missing 'PartitionName' attribute";
  569. delete ack;
  570. return( false );
  571. }
  572. delete ack;
  573. return( true );
  574. }
  575. //-----------------------------------------------------------------------------
  576. bool ClassAdCollectionClient::
  577. AddClassAd( const string &key, ClassAd *newAd )
  578. {
  579. ClassAd *rec, *ack;
  580. bool rval;
  581. // create the op record
  582. if( !( rec = _AddClassAd( currentXactionName, key, newAd ) ) ) {
  583. return( false );
  584. }
  585. // perform operation on server
  586. rval = SendOpToServer( ClassAdCollOp_AddClassAd, rec,
  587. ClassAdCollOp_AckClassAdOp, ack );
  588. rec->Remove( ATTR_AD );
  589. if( rec ) delete rec;
  590. if( ack ) delete ack;
  591. return( rval );
  592. }
  593. bool ClassAdCollectionClient::
  594. UpdateClassAd( const string &key, ClassAd *updAd )
  595. {
  596. ClassAd *rec, *ack;
  597. bool rval;
  598. // create the op record
  599. if( !( rec = _UpdateClassAd( currentXactionName, key, updAd ) ) ) {
  600. return( false );
  601. }
  602. // perform operation on server
  603. rval = SendOpToServer( ClassAdCollOp_UpdateClassAd, rec,
  604. ClassAdCollOp_AckClassAdOp, ack );
  605. rec->Remove( ATTR_AD );
  606. if( rec ) delete rec;
  607. if( ack ) delete ack;
  608. return( rval );
  609. }
  610. bool ClassAdCollectionClient::
  611. ModifyClassAd( const string &key, ClassAd *modAd )
  612. {
  613. ClassAd *rec, *ack;
  614. bool rval;
  615. // create the op record
  616. if( !( rec = _ModifyClassAd( currentXactionName, key, modAd ) ) ) {
  617. return( false );
  618. }
  619. // perform operation on server
  620. rval = SendOpToServer( ClassAdCollOp_ModifyClassAd, rec,
  621. ClassAdCollOp_AckClassAdOp, ack );
  622. rec->Remove( ATTR_AD );
  623. if( rec ) delete rec;
  624. if( ack ) delete ack;
  625. return( rval );
  626. }
  627. bool ClassAdCollectionClient::
  628. RemoveClassAd( const string &key )
  629. {
  630. ClassAd *rec, *ack;
  631. bool rval;
  632. // create the op record
  633. if( !( rec = _RemoveClassAd( currentXactionName, key ) ) ) {
  634. return( false );
  635. }
  636. // perform operation on server
  637. rval = SendOpToServer( ClassAdCollOp_RemoveClassAd, rec,
  638. ClassAdCollOp_AckClassAdOp, ack );
  639. if( rec ) delete rec;
  640. if( ack ) delete ack;
  641. return( rval );
  642. }
  643. ClassAd *ClassAdCollectionClient::
  644. GetClassAd( const string &key )
  645. {
  646. ClassAd rec, *ack=NULL, *ad;
  647. Value val;
  648. rec.InsertAttr( ATTR_OP_TYPE, ClassAdCollOp_GetClassAd );
  649. rec.InsertAttr( ATTR_KEY, key );
  650. if( !SendOpToServer( ClassAdCollOp_GetClassAd, &rec,
  651. ClassAdCollOp_AckReadOp, ack ) || CondorErrno != ERR_OK ) {
  652. if( ack ) delete ack;
  653. return( NULL );
  654. }
  655. if( !ack->EvaluateAttr( ATTR_AD, val ) || !val.IsClassAdValue( ad ) ) {
  656. delete ack;
  657. CondorErrno = ERR_BAD_SERVER_ACK;
  658. CondorErrMsg = "bad server ack; bad or missing 'Ad' attribute";
  659. return( NULL );
  660. }
  661. ack->Remove( ATTR_AD );
  662. delete ack;
  663. return( ad );
  664. }
  665. bool ClassAdCollectionClient::
  666. SendOpToServer( int opType, ClassAd *rec, int expectedOpType, ClassAd *&ack )
  667. {
  668. int ackOpType, serverErrno;
  669. string buffer, serverErrMsg;
  670. char *tmp;
  671. bool dontWantAck;
  672. ack = NULL;
  673. // check server connection
  674. if( !serverSock ) {
  675. CondorErrno = ERR_CLIENT_NOT_CONNECTED;
  676. CondorErrMsg = "client not connected to server";
  677. return( false );
  678. }
  679. // do we or don't we want an ack for this operation?
  680. dontWantAck = opType == ClassAdCollOp_AbortTransaction ||
  681. opType == ClassAdCollOp_ForgetTransaction ||
  682. ( ( opType >= __ClassAdCollOp_ClassAdOps_Begin__ &&
  683. opType <= __ClassAdCollOp_ClassAdOps_End__ ) &&
  684. amode == DONT_WANT_ACKS );
  685. if( !dontWantAck && rec ) {
  686. rec->InsertAttr( "WantAck", true );
  687. }
  688. // if in transaction or we need acks or we're doing a transaction op,
  689. // make sure we're using tcp
  690. if( ( currentXactionName != "" || !dontWantAck ||
  691. ( opType>=__ClassAdCollOp_XactionOps_Begin__ &&
  692. opType <= __ClassAdCollOp_XactionOps_End__ ) ) &&
  693. serverSock->type( ) == Stream::safe_sock ) {
  694. CondorErrno = ERR_BAD_CONNECTION_TYPE;
  695. CondorErrMsg = "cannot perform operation over unreliable connection";
  696. return( false );
  697. }
  698. // send op record to server (some commands don't have rec classads)
  699. serverSock->encode( );
  700. if( rec ) unparser.Unparse( buffer, rec );
  701. if( !serverSock->put(opType) ||
  702. !(rec ? serverSock->put((char*)buffer.c_str()) : true ) ||
  703. !serverSock->end_of_message( ) ) {
  704. CondorErrno = ERR_COMMUNICATION_ERROR;
  705. CondorErrMsg = "failed to send [" +
  706. string(ClassAdCollectionInterface::GetOpString(opType)) +
  707. "] to server";
  708. return( false );
  709. }
  710. // no ack required?
  711. if( dontWantAck ) {
  712. ack = NULL;
  713. return( true );
  714. }
  715. // ack required
  716. serverSock->decode( );
  717. tmp = NULL;
  718. if( !serverSock->get( ackOpType ) || !serverSock->get( tmp ) ||
  719. !serverSock->end_of_message( ) ) {
  720. CondorErrno = ERR_COMMUNICATION_ERROR;
  721. CondorErrMsg = "failed to receive ack from server";
  722. return( false );
  723. }
  724. // make sure we got the right ack
  725. buffer = tmp;
  726. free( tmp );
  727. ack = NULL;
  728. // expected type?
  729. if( ackOpType != expectedOpType ) {
  730. CondorErrno = ERR_BAD_SERVER_ACK;
  731. CondorErrMsg = "expected [" +
  732. string(ClassAdCollectionInterface::GetOpString(expectedOpType)) +
  733. "] but got [" +
  734. string(ClassAdCollectionInterface::GetOpString(ackOpType)) +
  735. "]";
  736. return( false );
  737. }
  738. // valid classad?
  739. if( !(ack = parser.ParseClassAd( buffer ) ) ) {
  740. CondorErrno = ERR_BAD_SERVER_ACK;
  741. CondorErrMsg = "bad server ack --- " + CondorErrMsg;
  742. return( false );
  743. }
  744. // server side error?
  745. if( !ack->EvaluateAttrInt( "CondorErrno", serverErrno ) ||
  746. !ack->EvaluateAttrString( "CondorErrMsg", serverErrMsg ) ) {
  747. CondorErrno = ERR_BAD_SERVER_ACK;
  748. CondorErrMsg = "missing error information";
  749. return( false );
  750. }
  751. CondorErrno = serverErrno;
  752. CondorErrMsg = serverErrMsg;
  753. // done
  754. return( true );
  755. }
  756. bool ClassAdCollectionClient::
  757. IsMyActiveTransaction( const string &transactionName )
  758. {
  759. LocalXactionTable::iterator itr = localXactionTable.find(transactionName);
  760. return( itr != localXactionTable.end( ) && itr->second &&
  761. itr->second->GetXactionState( ) == ClientTransaction::ACTIVE );
  762. }
  763. void ClassAdCollectionClient::
  764. GetMyActiveTransactions( vector<string>& xactions )
  765. {
  766. LocalXactionTable::iterator itr;
  767. xactions.clear( );
  768. for( itr=localXactionTable.begin( ); itr!=localXactionTable.end( ); itr++ ){
  769. if( itr->second && itr->second->GetXactionState( ) ==
  770. ClientTransaction::ACTIVE ) {
  771. xactions.push_back( itr->first );
  772. }
  773. }
  774. }
  775. bool ClassAdCollectionClient::
  776. IsMyPendingTransaction( const string &transactionName )
  777. {
  778. LocalXactionTable::iterator itr = localXactionTable.find(transactionName);
  779. return( itr != localXactionTable.end( ) && itr->second &&
  780. itr->second->GetXactionState( ) == ClientTransaction::PENDING );
  781. }
  782. void ClassAdCollectionClient::
  783. GetMyPendingTransactions( vector<string>& xactions )
  784. {
  785. LocalXactionTable::iterator itr;
  786. xactions.clear( );
  787. for( itr=localXactionTable.begin( ); itr!=localXactionTable.end( ); itr++ ){
  788. if( itr->second && itr->second->GetXactionState( ) ==
  789. ClientTransaction::PENDING ) {
  790. xactions.push_back( itr->first );
  791. }
  792. }
  793. }
  794. bool ClassAdCollectionClient::
  795. IsMyCommittedTransaction( const string &transactionName )
  796. {
  797. return( IsMyPendingTransaction( transactionName ) &&
  798. IsCommittedTransaction( transactionName ) );
  799. }
  800. void ClassAdCollectionClient::
  801. GetMyCommittedTransactions( vector<string>& xactions )
  802. {
  803. vector<string> pending;
  804. vector<string> committed;
  805. vector<string>::iterator pitr, citr;
  806. GetMyPendingTransactions( pending );
  807. GetAllCommittedTransactions( committed );
  808. // for each pending xaction ...
  809. for( pitr = pending.begin(); pitr != pending.end( ); pitr++ ) {
  810. // see if the xaction is also committed
  811. for( citr = committed.begin( ); citr != committed.end( ); citr++ ) {
  812. if( *citr == *pitr ) {
  813. // yes ... this is one of my committed xactions
  814. xactions.push_back( *pitr );
  815. break;
  816. }
  817. }
  818. }
  819. }
  820. bool ClassAdCollectionClient::
  821. _CheckTransactionState( int command, const string &xactionName, Value &result )
  822. {
  823. ClassAd rec, *ack=NULL;
  824. rec.InsertAttr( ATTR_OP_TYPE, command );
  825. rec.InsertAttr( ATTR_XACTION_NAME, xactionName );
  826. if( !SendOpToServer( command, &rec, ClassAdCollOp_AckReadOp, ack ) ||
  827. CondorErrno != ERR_OK ) {
  828. if( ack ) delete ack;
  829. return( false );
  830. }
  831. if( !ack->EvaluateAttr( "Result", result ) ) {
  832. delete ack;
  833. CondorErrno = ERR_BAD_SERVER_ACK;
  834. CondorErrMsg = "bad server ack --- missing 'Result' attribute";
  835. return( false );
  836. }
  837. delete ack;
  838. return( true );
  839. }
  840. bool ClassAdCollectionClient::
  841. IsActiveTransaction( const string &xactionName )
  842. {
  843. Value val;
  844. bool b;
  845. return( _CheckTransactionState( ClassAdCollOp_IsActiveTransaction,
  846. xactionName, val ) && val.IsBooleanValue(b) && b );
  847. }
  848. bool ClassAdCollectionClient::
  849. IsCommittedTransaction( const string &xactionName )
  850. {
  851. Value val;
  852. bool b;
  853. return( _CheckTransactionState( ClassAdCollOp_IsCommittedTransaction,
  854. xactionName, val ) && val.IsBooleanValue(b) && b );
  855. }
  856. bool ClassAdCollectionClient::
  857. GetServerXactionState( const string &xactionName, int &state )
  858. {
  859. Value val;
  860. return( _CheckTransactionState( ClassAdCollOp_GetServerTransactionState,
  861. xactionName, val ) && val.IsIntegerValue( state ) );
  862. }
  863. bool ClassAdCollectionClient::
  864. _GetAllxxxTransactions( int command, vector<string>& xactions )
  865. {
  866. ClassAd *ack;
  867. Value val;
  868. ExprList *el;
  869. ExprListIterator itr;
  870. string strVal;
  871. xactions.clear( );
  872. if( !SendOpToServer( command, NULL, ClassAdCollOp_AckReadOp, ack ) ) {
  873. if( ack ) delete ack;
  874. return( false );
  875. }
  876. if( !ack->EvaluateAttr( command==ClassAdCollOp_GetAllActiveTransactions ?
  877. "ActiveTransactions":"CommittedTransactions", val ) ||
  878. !val.IsListValue( el ) ) {
  879. CondorErrno = ERR_BAD_SERVER_ACK;
  880. CondorErrMsg = "bad server ack --- bad or missing transaction names";
  881. return( false );
  882. }
  883. itr.Initialize( el );
  884. while( !itr.IsAfterLast( ) ) {
  885. if( !itr.CurrentValue( val ) || !val.IsStringValue( strVal ) ) {
  886. delete ack;
  887. xactions.clear( );
  888. return( false );
  889. }
  890. xactions.push_back( strVal );
  891. itr.NextExpr( );
  892. }
  893. return( true );
  894. }
  895. bool ClassAdCollectionClient::
  896. GetAllActiveTransactions( vector<string>& xactions )
  897. {
  898. return( _GetAllxxxTransactions( ClassAdCollOp_GetAllActiveTransactions,
  899. xactions ) );
  900. }
  901. bool ClassAdCollectionClient::
  902. GetAllCommittedTransactions( vector<string>& xactions )
  903. {
  904. return( _GetAllxxxTransactions( ClassAdCollOp_GetAllCommittedTransactions,
  905. xactions ) );
  906. }
  907. bool ClassAdCollectionClient::
  908. GetViewInfo( const string &viewName, ClassAd*& vi )
  909. {
  910. ClassAd rec, *ack=NULL;
  911. Value val;
  912. rec.InsertAttr( ATTR_OP_TYPE, ClassAdCollOp_GetViewInfo );
  913. rec.InsertAttr( ATTR_VIEW_NAME, viewName );
  914. if( !SendOpToServer( ClassAdCollOp_GetViewInfo, &rec,
  915. ClassAdCollOp_AckReadOp, ack ) || CondorErrno != ERR_OK ) {
  916. if( ack ) delete ack;
  917. return( false );
  918. }
  919. if( !ack->EvaluateAttr( ATTR_VIEW_INFO, val ) || !val.IsClassAdValue(vi) ){
  920. CondorErrno = ERR_BAD_SERVER_ACK;
  921. CondorErrMsg = "bad server ack; bad or missing 'ViewInfo' attribute";
  922. delete ack;
  923. vi = NULL;
  924. return( false );
  925. }
  926. ack->Remove( ATTR_VIEW_INFO );
  927. delete ack;
  928. return( true );
  929. }
  930. bool ClassAdCollectionClient::
  931. LogState( FILE* fp )
  932. {
  933. LocalXactionTable::iterator itr;
  934. ClientTransaction *xaction;
  935. ClassAd rec;
  936. string xactionName, serverAddr, buffer;
  937. int serverPort;
  938. // log pending transactions only
  939. for( itr=localXactionTable.begin(); itr!=localXactionTable.end( ); itr++ ){
  940. xaction = itr->second;
  941. if( xaction->GetXactionState() != ClientTransaction::PENDING ) continue;
  942. xaction->GetXactionName( xactionName );
  943. xaction->GetServerAddr( serverAddr, serverPort );
  944. rec.InsertAttr( ATTR_OP_TYPE, ClassAdCollOp_CommitTransaction );
  945. rec.InsertAttr( ATTR_XACTION_NAME, xactionName );
  946. rec.InsertAttr( "ServerAddr", serverAddr );
  947. rec.InsertAttr( "ServerPort", serverPort );
  948. buffer = "";
  949. unparser.Unparse( buffer, &rec );
  950. if( fprintf( fp, "%s\n", buffer.c_str( ) ) < 0 ) {
  951. CondorErrno = ERR_FILE_WRITE_FAILED;
  952. CondorErrMsg = "failed to write to log";
  953. return( false );
  954. }
  955. }
  956. return( true );
  957. }
  958. } // classad