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