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