Added new message type "Unknown alias/DP" (type n. 7)
[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
111 ClassImp(AliDCSClient)
112
113 const char* AliDCSClient::fgkBadStateString = "BadState";
114 const char* AliDCSClient::fgkInvalidParameterString = "InvalidParameter";
115 const char* AliDCSClient::fgkTimeoutString = "Timeout";
116 const char* AliDCSClient::fgkBadMessageString = "BadMessage";
117 const char* AliDCSClient::fgkCommErrorString = "CommunicationError";
118 const char* AliDCSClient::fgkServerErrorString = "ServerError";
119 const char* AliDCSClient::fgkUnknownDPString = "UnknownAlias/DP";
120
121 //______________________________________________________________________
122 AliDCSClient::AliDCSClient(const char* host, Int_t port, UInt_t timeout,
123         Int_t retries, Int_t multiSplit):
124         fSocket(NULL), fHost(host), fPort(port), fTimeout(timeout), fRetries(retries), fMultiSplit(multiSplit),
125         fServerErrorCode(AliDCSMessage::kNoneError), fServerError(""), fResultErrorCode(0)
126 {
127         // 
128         // host: DCS server host
129         // port: DCS server port
130         // timeout: in case of communication error or socket read/write this 
131         //              timeout will be used before the next try is made. 
132         // retries: the number of retries after which the connection is 
133         //              is considered as invalid and error is returned.
134         //
135 }
136
137 //______________________________________________________________________
138 AliDCSClient::~AliDCSClient() 
139 {
140         // destructor
141
142         Close();
143 }
144
145 //______________________________________________________________________
146 Bool_t AliDCSClient::Connect()
147 {
148         //  connects to the AMANDA server
149         
150         Close();
151         
152         Int_t tries = 0;        
153         while (tries < fRetries) 
154         {
155                 fSocket = new TSocket(fHost, fPort);
156                 if (fSocket->IsValid()) 
157                 {
158                         AliDebug(1, Form("Connected to %s:%d", fHost.Data(), fPort));
159                         fSocket->SetOption(kNoBlock, 1);
160                         return kTRUE;
161                 }
162
163                 AliDebug(1, Form("Connection timeout! tries <%d> ...", tries));
164
165                 delete fSocket;
166                 fSocket = NULL;
167
168                 gSystem->Sleep(fTimeout);
169                 tries ++;
170         }
171         
172         return kFALSE;
173 }
174
175 //______________________________________________________________________
176 Int_t AliDCSClient::SendBuffer(const char* buffer, Int_t size) 
177 {
178 // send buffer containing the message to the DCS server
179
180         Int_t sentSize = 0;
181         Int_t tries = 0;
182
183         while (sentSize < size && tries < fRetries) {
184
185                 Int_t sResult = fSocket->Select(TSocket::kWrite, fTimeout);
186
187                 if (sResult == 0) {
188                         AliDebug(1, Form("Timeout! tries <%d> ...", tries));
189                         tries ++;
190                         continue;
191
192                 } else if (sResult < 0) {
193                         AliDebug(1, Form("Communication error <%d>!", 
194                                         fSocket->GetErrorCode()));
195                         return AliDCSClient::fgkCommError;
196                 }
197
198                 sResult = fSocket->SendRaw(buffer + sentSize, size - sentSize,
199                                         kDontBlock);
200
201                 if (sResult > 0) {
202                         sentSize += sResult;
203                 } else {
204                         AliDebug(1, Form("Communication error <%d>!",
205                                         fSocket->GetErrorCode()));
206                         return AliDCSClient::fgkCommError;
207                 }
208         }
209
210         if (tries == fRetries) {
211                 return AliDCSClient::fgkTimeout;
212         }
213
214         return sentSize;
215 }
216
217 //______________________________________________________________________
218 Int_t AliDCSClient::ReceiveBuffer(char* buffer, Int_t size) 
219 {
220 // Receive message from the DCS server and fill buffer
221
222         Int_t receivedSize = 0;
223         Int_t tries = 0;
224
225         while (receivedSize < size && tries < fRetries) {
226
227                 Int_t sResult = fSocket->Select(TSocket::kRead, fTimeout);
228
229                 if (sResult == 0) {
230                         AliDebug(1, Form("Timeout! tries <%d> ...", tries));
231                         tries ++;
232                         continue;
233
234                 } else if (sResult < 0) {
235                         AliDebug(1, Form("Communication error <%d>",
236                                         fSocket->GetErrorCode()));
237                         return AliDCSClient::fgkCommError;
238                 }
239
240                 sResult = fSocket->RecvRaw(buffer + receivedSize, 
241                         size - receivedSize, kDontBlock);
242
243                 if (sResult > 0) {
244                         receivedSize += sResult;
245                 } else {
246                         AliDebug(1, Form("Communication error <%d>",
247                                         fSocket->GetErrorCode()));
248                         return AliDCSClient::fgkCommError;
249                 }
250         }
251
252         if (tries == fRetries) {
253                 return AliDCSClient::fgkTimeout;
254         }
255
256         return receivedSize;
257 }
258
259 //______________________________________________________________________
260 Int_t AliDCSClient::SendMessage(AliDCSMessage& message) 
261 {
262 // send message to the DCS server
263
264         message.StoreToBuffer();
265
266         AliDebug(2, "Sending message.\n"); 
267         message.Print();
268
269         return SendBuffer(message.GetMessage(), message.GetMessageSize());
270 }
271
272 //______________________________________________________________________
273 Int_t AliDCSClient::ReceiveMessage(AliDCSMessage& message)
274 {
275 // receive message from the DCS server
276         
277         char header[HEADER_SIZE];
278
279         Int_t sResult;
280
281         if ((sResult = ReceiveBuffer(header, HEADER_SIZE)) < 0) {
282                 AliDebug(1, Form("Can't receive message header! Reason: %s", 
283                         GetErrorString(sResult)));
284                 return sResult;
285         }
286
287         if (!message.SetRawHeader(header)) {
288                 return AliDCSClient::fgkBadMessage;
289         }
290
291         if ((sResult = ReceiveBuffer(message.GetBody(), 
292                         message.GetBodySize())) < 0) {
293                 
294                 AliDebug(1, Form("Can't receive message body! Reason: %s", 
295                         GetErrorString(sResult)));
296                 return sResult;
297         }
298
299         message.LoadFromBuffer();
300
301         AliDebug(2, "Message received.");
302         message.Print();
303
304         return HEADER_SIZE + sResult;
305 }
306
307 //______________________________________________________________________
308 Int_t AliDCSClient::GetValues(AliDCSMessage::RequestType reqType,
309         const char* reqString, UInt_t startTime, UInt_t endTime, TObjArray* result)
310 {
311         // get array of DCS values from the DCS server
312         // reqString: alias name
313         // startTime, endTime: start time and end time of the query
314         // result: contains the array of retrieved AliDCSValue's
315
316         Connect();
317         
318         if (!IsConnected()) {
319                 AliError("Not connected!");
320                 return AliDCSClient::fgkBadState;
321         }
322
323         Int_t sResult = -1;
324         AliDCSMessage requestMessage;
325         requestMessage.CreateRequestMessage(reqType, startTime, endTime,
326                         reqString);
327
328         if ((sResult = SendMessage(requestMessage)) < 0) {
329                 AliError(Form("Can't send request message! Reason: %s",
330                         GetErrorString(sResult)));
331                 Close();
332                 return sResult;
333         }
334
335         Int_t receivedValues = 0;
336
337         while (1)
338         {
339                 Int_t tmp = 0;
340                 sResult = ReceiveValueSet(result, tmp);
341                 if (sResult <= 0)
342                         break;
343                 receivedValues += sResult;
344         }
345
346         Close();
347
348         return receivedValues;
349 }
350
351 //______________________________________________________________________
352 TMap* AliDCSClient::GetValues(AliDCSMessage::RequestType reqType,
353         const TSeqCollection* list, UInt_t startTime, UInt_t endTime,
354         Int_t startIndex, Int_t endIndex)
355 {
356         // get array of DCS values from the DCS server
357         // list, startTime, endTime: list of dp/alias names, start time and end time of the query
358         //
359         // Result: map containing the array of alias names. It will be filled with
360         // the values retrieved for each alias
361
362         TMap* result = new TMap;
363         result->SetOwner(1);
364
365         if (endIndex < 0 || endIndex > list->GetEntries())
366                 endIndex = list->GetEntries();
367
368         for (Int_t subsetBegin = startIndex; subsetBegin < endIndex; subsetBegin += fMultiSplit)
369         {
370                 Connect();
371
372                 if (!IsConnected())
373                 {
374                         AliError("Not connected!");
375                         delete result;
376                         fResultErrorCode = fgkBadState;
377                         return 0;
378                 }
379
380                 Int_t subsetEnd = subsetBegin + fMultiSplit;
381                 if (subsetEnd > endIndex)
382                     subsetEnd = endIndex;
383         
384                 AliDCSMessage requestMessage;
385                 if (fMultiSplit == 1)
386                 {
387                         // single dp request
388
389                         TObjString* aRequest = (TObjString*) list->At(subsetBegin);
390                         requestMessage.CreateRequestMessage(reqType, startTime, endTime, aRequest->String());
391                 }
392                 else
393                 {
394                         // multi dp request
395
396                         requestMessage.CreateMultiRequestMessage(reqType,
397                                 startTime, endTime);
398
399                         for (Int_t i=subsetBegin; i<subsetEnd; i++)
400                         {
401                                 TObjString* aRequest = (TObjString*) list->At(i);
402                                 if (!requestMessage.AddRequestString(aRequest->String()))
403                                 {
404                                         delete result;
405                                         fResultErrorCode = fgkBadMessage;
406                                         return 0;
407                                 }
408                         }
409                 }
410
411                 if ((fResultErrorCode = SendMessage(requestMessage)) < 0)
412                 {
413                         AliError(Form("Can't send request message! Reason: %s",
414                                 GetErrorString(fResultErrorCode)));
415                         Close();
416                         delete result;
417                         return 0;
418                 }
419
420                 while (1)
421                 {
422                         TObjArray* resultSet = new TObjArray();
423                         resultSet->SetOwner(1);
424
425                         Int_t ownerIndex = -1;
426                         fResultErrorCode = ReceiveValueSet(resultSet, ownerIndex);
427
428                         if (fResultErrorCode < 0)
429                         {
430                                 if (fResultErrorCode == fgkUnknownDP)
431                                 {
432                                         AliError(Form("%s",fServerError.Data()));
433                                 }
434                                 
435                                 AliError("Can't get values");
436
437                                 delete resultSet;
438                                 result->DeleteValues();
439                                 delete result;
440                                 return 0;
441                         }
442
443                         if (ownerIndex < 0)
444                         {
445                                 // no more values
446                                 delete resultSet;
447                                 break;
448                         }
449
450                         TObjString* aRequest = (TObjString*) list->At(ownerIndex + subsetBegin);
451                         //AliInfo(Form("Received %d values for entry %d, that is %s", resultSet->GetEntries(),
452                         //      ownerIndex + subsetBegin, aRequest->String().Data()));
453
454                         TObjArray* target = dynamic_cast<TObjArray*> (result->GetValue(aRequest));
455                         if (target)
456                         {
457                                 target->AddAll(resultSet);
458                                 //AliInfo(Form("Now we have %d entries", target->GetEntries()));
459                                 resultSet->SetOwner(0);
460                                 delete resultSet;
461                         }
462                         else
463                                 result->Add(aRequest, resultSet);
464                 }
465
466                 Close();
467
468                 Int_t nValues = 0;
469                 TObjArray* example = (TObjArray*) result->GetValue(list->At(subsetBegin));
470                 if (example)
471                         nValues = example->GetEntries();
472                 AliInfo(Form("Retrieved entries %d..%d (total %d..%d); E.g. %s has %d values collected",
473                         subsetBegin, subsetEnd-1, startIndex, endIndex-1, list->At(subsetBegin)->GetName(), nValues));
474         }
475
476         return result;
477 }
478         
479 //______________________________________________________________________
480 Int_t AliDCSClient::ReceiveValueSet(TObjArray* result, Int_t& ownerIndex)
481 {
482         // receive set of values
483
484         AliDCSMessage message;
485         Int_t sResult = ReceiveMessage(message);
486         if (sResult < 0)
487         {
488                 AliError(Form("Can't receive message! Reason: %s", GetErrorString(sResult)));
489                 return sResult;
490         }
491
492         if (message.GetType() == AliDCSMessage::kResultSet)
493         {
494                 // this was the last message
495                 ownerIndex = message.GetOwnerIndex();
496                 if (ownerIndex < 0)
497                         return 0;
498
499                 sResult = message.GetValues(result);
500
501 //              AliDCSMessage nextMessage;
502 //              nextMessage.CreateNextMessage();
503 // 
504 //              if ((fResultErrorCode = SendMessage(nextMessage)) < 0)
505 //              {
506 //                      AliError(Form("Can't send next message! Reason: %s",
507 //                              GetErrorString(fResultErrorCode)));
508 //                      Close();
509 //                      return AliDCSClient::fgkCommError;
510 //              }
511
512                 return sResult;
513         }
514         else if (message.GetType() == AliDCSMessage::kError)
515         {
516                 fServerErrorCode = message.GetErrorCode();
517                 fServerError = message.GetErrorString();
518
519                 return AliDCSClient::fgkServerError;
520         }
521         
522         else if (message.GetType() == AliDCSMessage::kUnknownDP)
523         {
524                 fServerError = message.GetErrorString();
525
526                 return AliDCSClient::fgkUnknownDP;
527         }
528         
529
530         AliError("Bad message type received!");
531         return AliDCSClient::fgkBadMessage;
532 }
533
534 //______________________________________________________________________
535 Int_t AliDCSClient::GetDPValues(const char* dpName, UInt_t startTime,
536                                 UInt_t endTime, TObjArray* result)
537 {
538         //
539         // Reads a values from the server which correspond to this
540         // DataPoint (dpName) in time interval (startTime - endTime).
541         // result: Collection of AliDCSValue which contains the read values.
542         //
543         // Returns:
544         //      If >= 0 , the number of values read.
545         //      if < 0, the error code which has occured during the read.
546         //
547
548         return GetValues(AliDCSMessage::kDPName, 
549                         dpName, startTime, endTime, result);
550 }
551
552 //______________________________________________________________________
553 Int_t AliDCSClient::GetAliasValues(const char* alias, UInt_t startTime,
554                                 UInt_t endTime, TObjArray* result)
555 {
556         //
557         // Reads a values from the server which correspond to this
558         // alias (alias) in time interval (startTime - endTime).
559         // result: Collection of AliDCSValue which contains the read values.
560         //
561         // Returns:
562         //      If >= 0 , the number of values read.
563         //      if < 0, the error code which has occured during the read.
564         //
565
566         return GetValues(AliDCSMessage::kAlias, 
567                         alias, startTime, endTime, result);
568 }
569
570 //______________________________________________________________________
571 TMap* AliDCSClient::GetDPValues(const TSeqCollection* dpList, UInt_t startTime, UInt_t endTime,
572         Int_t startIndex, Int_t endIndex) 
573 {
574         //
575         // For every entry (fron startIndex to endIndex) in dpList (which must be TObjString) 
576         // reads a valueSet. The key represents particular DataPoint to be read.
577         // For all DataPoints time interval (startTime - endTime) is used.
578         // After the read, the correspoding value for every key is a 
579         // TObjArray - collection of AliDCSValue, or result is an empty map in
580         // case of error.
581         // 
582         // Returns:
583         //      TMap of results, 0 in case of failure
584         //
585
586         return GetValues(AliDCSMessage::kDPName, dpList, startTime, endTime, startIndex, endIndex);
587 }
588
589 //______________________________________________________________________
590 TMap* AliDCSClient::GetAliasValues(const TSeqCollection* aliasList, UInt_t startTime, UInt_t endTime,
591         Int_t startIndex, Int_t endIndex)
592 {
593         //
594         // For every entry (fron startIndex to endIndex) in dpList (which must be TObjString) 
595         // reads a valueSet. The key represents particular Alias to be read.
596         // For all aliases time interval (startTime - endTime) is used.
597         // After the read, the correspoding value for every key is a 
598         // TObjArray - collection of AliDCSValue, or result is an empty map in
599         // case of error.
600         // 
601         // Returns:
602         //      TMap of results, 0 in case of failure
603         //
604
605         return GetValues(AliDCSMessage::kAlias, aliasList, startTime, endTime, startIndex, endIndex);
606 }
607
608 //______________________________________________________________________
609 Bool_t AliDCSClient::IsConnected() 
610 {
611         //
612         // Returns kTRUE if there is a valid connection to the server.
613         //
614
615         if (fSocket) {
616                 return fSocket->IsValid();
617         }
618
619         return kFALSE;
620 }
621
622 //______________________________________________________________________
623 void AliDCSClient::Close() 
624 {
625         //
626         // Close the connection.
627         //
628
629         if (fSocket) {
630                 fSocket->Close();
631                 delete fSocket;
632                 fSocket = 0;
633         }
634 }
635
636 //______________________________________________________________________
637 const char* AliDCSClient::GetErrorString(Int_t code) 
638 {
639         //
640         // Returns a short string describing the error code.
641         // code: the error code.
642         //
643         
644
645         switch (code) {
646                 case AliDCSClient::fgkBadState:
647                         return AliDCSClient::fgkBadStateString;
648
649                 case AliDCSClient::fgkInvalidParameter:
650                         return AliDCSClient::fgkInvalidParameterString;
651
652                 case AliDCSClient::fgkTimeout:
653                         return AliDCSClient::fgkTimeoutString;
654
655                 case AliDCSClient::fgkBadMessage:
656                         return AliDCSClient::fgkBadMessageString;
657         
658                 case AliDCSClient::fgkCommError:
659                         return AliDCSClient::fgkCommErrorString;
660
661                 case AliDCSClient::fgkServerError:
662                         return AliDCSClient::fgkServerErrorString;
663                 
664                 case AliDCSClient::fgkUnknownDP:
665                         return AliDCSClient::fgkUnknownDPString;
666
667                 default:
668                         AliErrorGeneral("AliDCSClient::GetErrorString",
669                                 "Unknown error code!");
670                         return "UnknownCode";
671         }
672 }
673