]> git.uio.no Git - u/mrichter/AliRoot.git/blob - SHUTTLE/DCSClient/AliDCSClient.cxx
Modifications for correct use of timeout and slightly improved error/debug output...
[u/mrichter/AliRoot.git] / SHUTTLE / DCSClient / AliDCSClient.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /*
17 $Log$
18 Revision 1.8  2007/10/17 17:43:02  acolla
19 nextMessage removed from client
20
21 Revision 1.7  2007/10/16 15:02:20  jgrosseo
22 fixed bug if zero values collected
23
24 Revision 1.6  2007/10/16 14:37:16  jgrosseo
25 changing to AMANDA protocol version 2
26
27 Revision 1.5  2007/10/05 12:40:55  acolla
28
29 Result error code added to AliDCSClient data members (it was "lost" with the new implementation of TMap* GetAliasValues and GetDPValues).
30
31 Revision 1.4  2007/09/14 16:46:14  jgrosseo
32 1) Connect and Close are called before and after each query, so one can
33 keep the same AliDCSClient object.
34 2) The splitting of a query is moved to GetDPValues/GetAliasValues.
35 3) Splitting interval can be specified in constructor
36
37 Revision 1.3  2007/09/11 16:42:02  jgrosseo
38 starting modifying AliDCSClient to transparently switch between single and multi query
39 first step: same alidcsclient can be used for several queries
40
41 Revision 1.2  2007/06/09 13:01:09  jgrosseo
42 Switching to retrieval of several DCS DPs at a time (multiDPrequest)
43
44 Revision 1.1  2006/11/06 14:22:47  jgrosseo
45 major update (Alberto)
46 o) reading of run parameters from the logbook
47 o) online offline naming conversion
48 o) standalone DCSclient package
49
50 Revision 1.6  2006/10/02 16:38:39  jgrosseo
51 update (alberto):
52 fixed memory leaks
53 storing of objects that failed to be stored to the grid before
54 interfacing of shuttle status table in daq system
55
56 Revision 1.5  2006/08/15 10:50:00  jgrosseo
57 effc++ corrections (alberto)
58
59 Revision 1.4  2006/07/04 14:59:57  jgrosseo
60 revision of AliDCSValue: Removed wrapper classes, reduced storage size per value by factor 2
61
62 Revision 1.3  2006/06/12 09:11:16  jgrosseo
63 coding conventions (Alberto)
64
65 Revision 1.2  2006/03/07 07:52:34  hristov
66 New version (B.Yordanov)
67
68 Revision 1.3  2005/11/17 17:47:34  byordano
69 TList changed to TObjArray
70
71 Revision 1.2  2005/11/17 14:43:23  byordano
72 import to local CVS
73
74 Revision 1.1.1.1  2005/10/28 07:33:58  hristov
75 Initial import as subdirectory in AliRoot
76
77 Revision 1.1.1.1  2005/09/12 22:11:40  byordano
78 SHUTTLE package
79
80 Revision 1.3  2005/08/30 10:53:23  byordano
81 some more descriptions added
82
83 */
84
85 //
86 // This class represents the AliDCSClient.
87 // The client used for data retrieval from DCS server.
88 // There are two way for retrieving data from the server.
89 //      1) asking for DP (DataPoint) - usually changed frequently.
90 //      2) asking for Alias (Alias) - alias should be the same through whole
91 //              experimnet.
92 //              
93 // There are two type of read operations:
94 //      Asking for single alias/dp or asking for set of aliases/dp
95 //
96 // In case of ServerError the coresponding error code and 
97 // error string (description) could be got by GetServerErrorCode() and
98 // GetServerErrorString()
99 //
100
101 #include "AliDCSClient.h"
102 #include "AliDCSValue.h"
103 #include "AliLog.h"
104
105 #include <TSocket.h>
106 #include <TObjArray.h>
107 #include <TMap.h>
108 #include <TObjString.h>
109 #include <TSystem.h>
110 #include <TTimeStamp.h>
111
112 ClassImp(AliDCSClient)
113
114 const char* AliDCSClient::fgkBadStateString = "BadState";
115 const char* AliDCSClient::fgkInvalidParameterString = "InvalidParameter";
116 const char* AliDCSClient::fgkTimeoutString = "Timeout";
117 const char* AliDCSClient::fgkBadMessageString = "BadMessage";
118 const char* AliDCSClient::fgkCommErrorString = "CommunicationError";
119 const char* AliDCSClient::fgkServerErrorString = "ServerError";
120 const char* AliDCSClient::fgkUnknownDPString = "UnknownAlias/DP";
121
122 //______________________________________________________________________
123 AliDCSClient::AliDCSClient(const char* host, Int_t port, UInt_t timeout,
124         Int_t retries, Int_t multiSplit):
125         fSocket(NULL), fHost(host), fPort(port), fTimeout(timeout), fRetries(retries), fMultiSplit(multiSplit),
126         fServerErrorCode(AliDCSMessage::kNoneError), fServerError(""), fResultErrorCode(0)
127 {
128         // 
129         // host: DCS server host
130         // port: DCS server port
131         // timeout: in case of communication error or socket read/write this 
132         //              timeout will be used before the next try is made. 
133         // retries: the number of retries after which the connection is 
134         //              is considered as invalid and error is returned.
135         //
136 }
137
138 //______________________________________________________________________
139 AliDCSClient::~AliDCSClient() 
140 {
141         // destructor
142
143         Close();
144 }
145
146 //______________________________________________________________________
147 Bool_t AliDCSClient::Connect()
148 {
149         //  connects to the AMANDA server
150         
151         Close();
152         
153         Int_t tries = 0;
154         Int_t sleeptime=300;
155         
156         while (tries < fRetries) 
157         {
158                 fSocket = new TSocket(fHost, fPort);
159                         
160                 if (fSocket && fSocket->IsValid()) 
161                 {
162                         AliDebug(1, Form("%s  *** Connected to %s:%d", TTimeStamp(time(0)).AsString("s"), fHost.Data(), fPort));
163                         fSocket->SetOption(kNoBlock, 1);
164                         return kTRUE;
165                 }
166
167                 AliError(Form("%d *** Connection to AMANDA server failed! Tried <%d> times ...", tries+1));
168                 if(tries<fRetries-1) AliInfo(Form("%d *** Waiting %d seconds before next retry.", sleeptime));
169
170                 delete fSocket;
171                 fSocket = NULL;
172
173                 gSystem->Sleep(sleeptime);
174                 tries ++;
175         }
176         
177         return kFALSE;
178 }
179
180 //______________________________________________________________________
181 Int_t AliDCSClient::SendBuffer(const char* buffer, Int_t size) 
182 {
183 // send buffer containing the message to the DCS server
184
185         Int_t sentSize = 0;
186         Int_t tries = 0;
187
188         while (sentSize < size && tries < fRetries) {
189
190                 Int_t sResult = fSocket->Select(TSocket::kWrite, fTimeout*1000); //timeout for TSocket::Select is in msec
191
192                 if (sResult == 0) {
193                         AliDebug(1, Form("Timeout! tries <%d> ...", tries));
194                         tries ++;
195                         continue;
196
197                 } else if (sResult < 0) {
198                         AliDebug(1, Form("Communication error <%d>!", 
199                                         fSocket->GetErrorCode()));
200                         return AliDCSClient::fgkCommError;
201                 }
202
203                 sResult = fSocket->SendRaw(buffer + sentSize, size - sentSize,
204                                         kDontBlock);
205
206                 if (sResult > 0) {
207                         sentSize += sResult;
208                 } else {
209                         AliDebug(1, Form("Communication error <%d>!",
210                                         fSocket->GetErrorCode()));
211                         return AliDCSClient::fgkCommError;
212                 }
213         }
214
215         if (tries == fRetries) {
216                 return AliDCSClient::fgkTimeout;
217         }
218
219         return sentSize;
220 }
221
222 //______________________________________________________________________
223 Int_t AliDCSClient::ReceiveBuffer(char* buffer, Int_t size) 
224 {
225 // Receive message from the DCS server and fill buffer
226
227         Int_t receivedSize = 0;
228         Int_t tries = 0;
229
230         while (receivedSize < size && tries < fRetries) {
231
232                 Int_t sResult = fSocket->Select(TSocket::kRead, fTimeout*1000); //timeout for TSocket::Select is in msec
233
234                 if (sResult == 0) {
235                         AliDebug(1, Form("Time when timing out: %s   Timeout value: %d seconds",TTimeStamp(time(0)).AsString("s"),fTimeout));
236                         AliDebug(1, Form("Timeout! tries <%d> ...", tries));
237                         tries ++;
238                         continue;
239
240                 } else if (sResult < 0) {
241                         AliDebug(1, Form("Communication error <%d>",
242                                         fSocket->GetErrorCode()));
243                         return AliDCSClient::fgkCommError;
244                 }
245
246                 sResult = fSocket->RecvRaw(buffer + receivedSize, 
247                         size - receivedSize, kDontBlock);
248
249                 if (sResult > 0) {
250                         receivedSize += sResult;
251                 } else {
252                         AliDebug(1, Form("Communication error <%d>",
253                                         fSocket->GetErrorCode()));
254                         return AliDCSClient::fgkCommError;
255                 }
256         }
257
258         if (tries == fRetries) {
259                 return AliDCSClient::fgkTimeout;
260         }
261
262         return receivedSize;
263 }
264
265 //______________________________________________________________________
266 Int_t AliDCSClient::SendMessage(AliDCSMessage& message) 
267 {
268 // send message to the DCS server
269
270         message.StoreToBuffer();
271
272         AliDebug(2, "Sending message.\n"); 
273         message.Print();
274
275         return SendBuffer(message.GetMessage(), message.GetMessageSize());
276 }
277
278 //______________________________________________________________________
279 Int_t AliDCSClient::ReceiveMessage(AliDCSMessage& message)
280 {
281 // receive message from the DCS server
282         
283         char header[HEADER_SIZE];
284
285         Int_t sResult;
286
287         if ((sResult = ReceiveBuffer(header, HEADER_SIZE)) < 0) {
288                 AliDebug(1, Form("Can't receive message header! Reason: %s", 
289                         GetErrorString(sResult)));
290                 return sResult;
291         }
292
293         if (!message.SetRawHeader(header)) {
294                 return AliDCSClient::fgkBadMessage;
295         }
296
297         if ((sResult = ReceiveBuffer(message.GetBody(), 
298                         message.GetBodySize())) < 0) {
299                 
300                 AliDebug(1, Form("Can't receive message body! Reason: %s", 
301                         GetErrorString(sResult)));
302                 return sResult;
303         }
304
305         message.LoadFromBuffer();
306
307         AliDebug(2, "Message received.");
308         message.Print();
309
310         return HEADER_SIZE + sResult;
311 }
312
313 //______________________________________________________________________
314 Int_t AliDCSClient::GetValues(AliDCSMessage::RequestType reqType,
315         const char* reqString, UInt_t startTime, UInt_t endTime, TObjArray* result)
316 {
317         // get array of DCS values from the DCS server
318         // reqString: alias name
319         // startTime, endTime: start time and end time of the query
320         // result: contains the array of retrieved AliDCSValue's
321
322         Connect();
323         
324         if (!IsConnected()) {
325                 AliError("Not connected!");
326                 return AliDCSClient::fgkBadState;
327         }
328
329         Int_t sResult = -1;
330         AliDCSMessage requestMessage;
331         requestMessage.CreateRequestMessage(reqType, startTime, endTime,
332                         reqString);
333
334         if ((sResult = SendMessage(requestMessage)) < 0) {
335                 AliError(Form("Can't send request message! Reason: %s",
336                         GetErrorString(sResult)));
337                 Close();
338                 return sResult;
339         }
340
341         Int_t receivedValues = 0;
342
343         while (1)
344         {
345                 Int_t tmp = 0;
346                 sResult = ReceiveValueSet(result, tmp);
347                 if (sResult <= 0)
348                         break;
349                 receivedValues += sResult;
350         }
351
352         Close();
353
354         return receivedValues;
355 }
356
357 //______________________________________________________________________
358 TMap* AliDCSClient::GetValues(AliDCSMessage::RequestType reqType,
359         const TSeqCollection* list, UInt_t startTime, UInt_t endTime,
360         Int_t startIndex, Int_t endIndex)
361 {
362         // get array of DCS values from the DCS server
363         // list, startTime, endTime: list of dp/alias names, start time and end time of the query
364         //
365         // Result: map containing the array of alias names. It will be filled with
366         // the values retrieved for each alias
367
368         TMap* result = new TMap;
369         result->SetOwner(1);
370
371         if (endIndex < 0 || endIndex > list->GetEntries())
372                 endIndex = list->GetEntries();
373
374         for (Int_t subsetBegin = startIndex; subsetBegin < endIndex; subsetBegin += fMultiSplit)
375         {
376                 Connect();
377
378                 if (!IsConnected())
379                 {
380                         AliError("Not connected!");
381                         delete result;
382                         fResultErrorCode = fgkBadState;
383                         return 0;
384                 }
385
386                 Int_t subsetEnd = subsetBegin + fMultiSplit;
387                 if (subsetEnd > endIndex)
388                     subsetEnd = endIndex;
389         
390                 AliDCSMessage requestMessage;
391                 if (fMultiSplit == 1)
392                 {
393                         // single dp request
394
395                         TObjString* aRequest = (TObjString*) list->At(subsetBegin);
396                         requestMessage.CreateRequestMessage(reqType, startTime, endTime, aRequest->String());
397                 }
398                 else
399                 {
400                         // multi dp request
401
402                         requestMessage.CreateMultiRequestMessage(reqType,
403                                 startTime, endTime);
404
405                         for (Int_t i=subsetBegin; i<subsetEnd; i++)
406                         {
407                                 TObjString* aRequest = (TObjString*) list->At(i);
408                                 if (!requestMessage.AddRequestString(aRequest->String()))
409                                 {
410                                         delete result;
411                                         fResultErrorCode = fgkBadMessage;
412                                         return 0;
413                                 }
414                         }
415                 }
416
417                 if ((fResultErrorCode = SendMessage(requestMessage)) < 0)
418                 {
419                         AliError(Form("Can't send request message! Reason: %s",
420                                 GetErrorString(fResultErrorCode)));
421                         Close();
422                         delete result;
423                         return 0;
424                 }
425
426                 while (1)
427                 {
428                         TObjArray* resultSet = new TObjArray();
429                         resultSet->SetOwner(1);
430
431                         Int_t ownerIndex = -1;
432                         fResultErrorCode = ReceiveValueSet(resultSet, ownerIndex);
433
434                         if (fResultErrorCode < 0)
435                         {
436                                 if (fResultErrorCode == fgkUnknownDP)
437                                 {
438                                         AliError(Form("%s",fServerError.Data()));
439                                 }
440                                 
441                                 AliError("Can't get values");
442
443                                 delete resultSet;
444                                 result->DeleteValues();
445                                 delete result;
446                                 return 0;
447                         }
448
449                         if (ownerIndex < 0)
450                         {
451                                 // no more values
452                                 delete resultSet;
453                                 break;
454                         }
455
456                         TObjString* aRequest = (TObjString*) list->At(ownerIndex + subsetBegin);
457                         //AliInfo(Form("Received %d values for entry %d, that is %s", resultSet->GetEntries(),
458                         //      ownerIndex + subsetBegin, aRequest->String().Data()));
459
460                         TObjArray* target = dynamic_cast<TObjArray*> (result->GetValue(aRequest));
461                         if (target)
462                         {
463                                 target->AddAll(resultSet);
464                                 //AliInfo(Form("Now we have %d entries", target->GetEntries()));
465                                 resultSet->SetOwner(0);
466                                 delete resultSet;
467                         }
468                         else
469                                 result->Add(aRequest, resultSet);
470                 }
471
472                 Close();
473
474                 Int_t nValues = 0;
475                 TObjArray* example = (TObjArray*) result->GetValue(list->At(subsetBegin));
476                 if (example)
477                         nValues = example->GetEntries();
478                 AliInfo(Form("Retrieved entries %d..%d (total %d..%d); E.g. %s has %d values collected",
479                         subsetBegin, subsetEnd-1, startIndex, endIndex-1, list->At(subsetBegin)->GetName(), nValues));
480         }
481
482         return result;
483 }
484         
485 //______________________________________________________________________
486 Int_t AliDCSClient::ReceiveValueSet(TObjArray* result, Int_t& ownerIndex)
487 {
488         // receive set of values
489
490         AliDCSMessage message;
491         Int_t sResult = ReceiveMessage(message);
492         if (sResult < 0)
493         {
494                 AliError(Form("Can't receive message! Reason: %s", GetErrorString(sResult)));
495                 return sResult;
496         }
497
498         if (message.GetType() == AliDCSMessage::kResultSet)
499         {
500                 // this was the last message
501                 ownerIndex = message.GetOwnerIndex();
502                 if (ownerIndex < 0)
503                         return 0;
504
505                 sResult = message.GetValues(result);
506
507 //              AliDCSMessage nextMessage;
508 //              nextMessage.CreateNextMessage();
509 // 
510 //              if ((fResultErrorCode = SendMessage(nextMessage)) < 0)
511 //              {
512 //                      AliError(Form("Can't send next message! Reason: %s",
513 //                              GetErrorString(fResultErrorCode)));
514 //                      Close();
515 //                      return AliDCSClient::fgkCommError;
516 //              }
517
518                 return sResult;
519         }
520         else if (message.GetType() == AliDCSMessage::kError)
521         {
522                 fServerErrorCode = message.GetErrorCode();
523                 fServerError = message.GetErrorString();
524
525                 return AliDCSClient::fgkServerError;
526         }
527         
528         else if (message.GetType() == AliDCSMessage::kUnknownDP)
529         {
530                 fServerError = message.GetErrorString();
531
532                 return AliDCSClient::fgkUnknownDP;
533         }
534         
535
536         AliError("Bad message type received!");
537         return AliDCSClient::fgkBadMessage;
538 }
539
540 //______________________________________________________________________
541 Int_t AliDCSClient::GetDPValues(const char* dpName, UInt_t startTime,
542                                 UInt_t endTime, TObjArray* result)
543 {
544         //
545         // Reads a values from the server which correspond to this
546         // DataPoint (dpName) in time interval (startTime - endTime).
547         // result: Collection of AliDCSValue which contains the read values.
548         //
549         // Returns:
550         //      If >= 0 , the number of values read.
551         //      if < 0, the error code which has occured during the read.
552         //
553
554         return GetValues(AliDCSMessage::kDPName, 
555                         dpName, startTime, endTime, result);
556 }
557
558 //______________________________________________________________________
559 Int_t AliDCSClient::GetAliasValues(const char* alias, UInt_t startTime,
560                                 UInt_t endTime, TObjArray* result)
561 {
562         //
563         // Reads a values from the server which correspond to this
564         // alias (alias) in time interval (startTime - endTime).
565         // result: Collection of AliDCSValue which contains the read values.
566         //
567         // Returns:
568         //      If >= 0 , the number of values read.
569         //      if < 0, the error code which has occured during the read.
570         //
571
572         return GetValues(AliDCSMessage::kAlias, 
573                         alias, startTime, endTime, result);
574 }
575
576 //______________________________________________________________________
577 TMap* AliDCSClient::GetDPValues(const TSeqCollection* dpList, UInt_t startTime, UInt_t endTime,
578         Int_t startIndex, Int_t endIndex) 
579 {
580         //
581         // For every entry (fron startIndex to endIndex) in dpList (which must be TObjString) 
582         // reads a valueSet. The key represents particular DataPoint to be read.
583         // For all DataPoints time interval (startTime - endTime) is used.
584         // After the read, the correspoding value for every key is a 
585         // TObjArray - collection of AliDCSValue, or result is an empty map in
586         // case of error.
587         // 
588         // Returns:
589         //      TMap of results, 0 in case of failure
590         //
591
592         return GetValues(AliDCSMessage::kDPName, dpList, startTime, endTime, startIndex, endIndex);
593 }
594
595 //______________________________________________________________________
596 TMap* AliDCSClient::GetAliasValues(const TSeqCollection* aliasList, UInt_t startTime, UInt_t endTime,
597         Int_t startIndex, Int_t endIndex)
598 {
599         //
600         // For every entry (fron startIndex to endIndex) in dpList (which must be TObjString) 
601         // reads a valueSet. The key represents particular Alias to be read.
602         // For all aliases time interval (startTime - endTime) is used.
603         // After the read, the correspoding value for every key is a 
604         // TObjArray - collection of AliDCSValue, or result is an empty map in
605         // case of error.
606         // 
607         // Returns:
608         //      TMap of results, 0 in case of failure
609         //
610
611         return GetValues(AliDCSMessage::kAlias, aliasList, startTime, endTime, startIndex, endIndex);
612 }
613
614 //______________________________________________________________________
615 Bool_t AliDCSClient::IsConnected() 
616 {
617         //
618         // Returns kTRUE if there is a valid connection to the server.
619         //
620
621         if (fSocket) {
622                 return fSocket->IsValid();
623         }
624
625         return kFALSE;
626 }
627
628 //______________________________________________________________________
629 void AliDCSClient::Close() 
630 {
631         //
632         // Close the connection.
633         //
634
635         if (fSocket) {
636                 AliDebug(1, Form("%s  *** Closing connection to %s:%d", TTimeStamp(time(0)).AsString("s"), fHost.Data(), fPort));
637                 fSocket->Close();
638                 delete fSocket;
639                 fSocket = 0;
640         }
641 }
642
643 //______________________________________________________________________
644 const char* AliDCSClient::GetErrorString(Int_t code) 
645 {
646         //
647         // Returns a short string describing the error code.
648         // code: the error code.
649         //
650         
651
652         switch (code) {
653                 case AliDCSClient::fgkBadState:
654                         return AliDCSClient::fgkBadStateString;
655
656                 case AliDCSClient::fgkInvalidParameter:
657                         return AliDCSClient::fgkInvalidParameterString;
658
659                 case AliDCSClient::fgkTimeout:
660                         return AliDCSClient::fgkTimeoutString;
661
662                 case AliDCSClient::fgkBadMessage:
663                         return AliDCSClient::fgkBadMessageString;
664         
665                 case AliDCSClient::fgkCommError:
666                         return AliDCSClient::fgkCommErrorString;
667
668                 case AliDCSClient::fgkServerError:
669                         return AliDCSClient::fgkServerErrorString;
670                 
671                 case AliDCSClient::fgkUnknownDP:
672                         return AliDCSClient::fgkUnknownDPString;
673
674                 default:
675                         AliErrorGeneral("AliDCSClient::GetErrorString",
676                                 "Unknown error code!");
677                         return "UnknownCode";
678         }
679 }
680