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