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