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