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