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