@@ -59,6 +59,9 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
59
59
*/
60
60
package org .dcache .webadmin .controller .impl ;
61
61
62
+ import com .google .common .base .Throwables ;
63
+ import com .google .common .util .concurrent .RateLimiter ;
64
+ import org .apache .wicket .util .lang .Exceptions ;
62
65
import org .slf4j .Logger ;
63
66
import org .slf4j .LoggerFactory ;
64
67
@@ -77,6 +80,8 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
77
80
import java .util .Properties ;
78
81
import java .util .concurrent .TimeUnit ;
79
82
83
+ import dmg .cells .nucleus .NoRouteToCellException ;
84
+
80
85
import org .dcache .cells .CellStub ;
81
86
import org .dcache .services .billing .histograms .ITimeFrameHistogramFactory ;
82
87
import org .dcache .services .billing .histograms .ITimeFrameHistogramFactory .Style ;
@@ -106,6 +111,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
106
111
*/
107
112
public final class StandardBillingService implements IBillingService , Runnable {
108
113
private static final Logger logger = LoggerFactory .getLogger (StandardBillingService .class );
114
+ private static final double ERRORS_PER_SECOND = 1.0 / 120.0 ;
109
115
110
116
/**
111
117
* injected
@@ -135,48 +141,78 @@ public final class StandardBillingService implements IBillingService, Runnable {
135
141
* refreshing can be done periodically by the daemon, or forced
136
142
* through the web interface directly
137
143
*/
144
+ private final RateLimiter rate = RateLimiter .create (ERRORS_PER_SECOND );
145
+
138
146
private long timeout ;
139
147
private int popupWidth ;
140
148
private int popupHeight ;
141
149
private long lastUpdate = System .currentTimeMillis ();
142
150
private Thread refresher ;
143
151
144
152
public List <TimeFrameHistogramData > load (PlotType plotType ,
145
- TimeFrame timeFrame ) {
153
+ TimeFrame timeFrame ) throws NoRouteToCellException ,
154
+ ServiceUnavailableException {
146
155
logger .debug ("remote fetch of {} {}" , plotType , timeFrame );
147
156
List <TimeFrameHistogramData > histograms = new ArrayList <>();
148
- switch (plotType ) {
149
- case BYTES_READ :
150
- add (client .getDcBytesHistogram (timeFrame , false ), histograms );
151
- add (client .getHsmBytesHistogram (timeFrame , false ), histograms );
152
- break ;
153
- case BYTES_WRITTEN :
154
- add (client .getDcBytesHistogram (timeFrame , true ), histograms );
155
- add (client .getHsmBytesHistogram (timeFrame , true ), histograms );
156
- break ;
157
- case BYTES_P2P :
158
- add (client .getP2pBytesHistogram (timeFrame ), histograms );
159
- break ;
160
- case TRANSFERS_READ :
161
- add (client .getDcTransfersHistogram (timeFrame , false ),
162
- histograms );
163
- add (client .getHsmTransfersHistogram (timeFrame , false ),
164
- histograms );
165
- break ;
166
- case TRANSFERS_WRITTEN :
167
- add (client .getDcTransfersHistogram (timeFrame , true ), histograms );
168
- add (client .getHsmTransfersHistogram (timeFrame , true ),
169
- histograms );
170
- break ;
171
- case TRANSFERS_P2P :
172
- add (client .getP2pTransfersHistogram (timeFrame ), histograms );
173
- break ;
174
- case CONNECTION_TIME :
175
- add (client .getDcConnectTimeHistograms (timeFrame ), histograms );
176
- break ;
177
- case CACHE_HITS :
178
- add (client .getHitHistograms (timeFrame ), histograms );
179
- break ;
157
+ try {
158
+ switch (plotType ) {
159
+ case BYTES_READ :
160
+ add (client .getDcBytesHistogram (timeFrame , false ),
161
+ histograms );
162
+ add (client .getHsmBytesHistogram (timeFrame , false ),
163
+ histograms );
164
+ break ;
165
+ case BYTES_WRITTEN :
166
+ add (client .getDcBytesHistogram (timeFrame , true ),
167
+ histograms );
168
+ add (client .getHsmBytesHistogram (timeFrame , true ),
169
+ histograms );
170
+ break ;
171
+ case BYTES_P2P :
172
+ add (client .getP2pBytesHistogram (timeFrame ),
173
+ histograms );
174
+ break ;
175
+ case TRANSFERS_READ :
176
+ add (client .getDcTransfersHistogram (timeFrame , false ),
177
+ histograms );
178
+ add (client .getHsmTransfersHistogram (timeFrame , false ),
179
+ histograms );
180
+ break ;
181
+ case TRANSFERS_WRITTEN :
182
+ add (client .getDcTransfersHistogram (timeFrame , true ),
183
+ histograms );
184
+ add (client .getHsmTransfersHistogram (timeFrame , true ),
185
+ histograms );
186
+ break ;
187
+ case TRANSFERS_P2P :
188
+ add (client .getP2pTransfersHistogram (timeFrame ),
189
+ histograms );
190
+ break ;
191
+ case CONNECTION_TIME :
192
+ add (client .getDcConnectTimeHistograms (timeFrame ),
193
+ histograms );
194
+ break ;
195
+ case CACHE_HITS :
196
+ add (client .getHitHistograms (timeFrame ),
197
+ histograms );
198
+ break ;
199
+ }
200
+ } catch (UndeclaredThrowableException ute ) {
201
+ Throwable cause
202
+ = Exceptions .findCause (ute , ServiceUnavailableException .class );
203
+ if (cause != null ) {
204
+ throw (ServiceUnavailableException )cause ;
205
+ }
206
+ cause = Exceptions .findCause (ute , NoRouteToCellException .class );
207
+ if (cause != null ) {
208
+ throw (NoRouteToCellException )cause ;
209
+ }
210
+ cause = ute .getCause ();
211
+ Throwables .propagateIfPossible (cause );
212
+ throw new RuntimeException ("Unexpected error: "
213
+ + "this is probably a bug. Please report "
214
+ + "to the dCache team." ,
215
+ cause );
180
216
}
181
217
return histograms ;
182
218
}
@@ -288,7 +324,8 @@ public void initialize() {
288
324
}
289
325
290
326
@ Override
291
- public void refresh () {
327
+ public void refresh () throws NoRouteToCellException ,
328
+ ServiceUnavailableException {
292
329
TimeFrame [] timeFrames = generateTimeFrames ();
293
330
for (int tFrame = 0 ; tFrame < timeFrames .length ; tFrame ++) {
294
331
Date low = timeFrames [tFrame ].getLow ();
@@ -304,29 +341,25 @@ public void refresh() {
304
341
@ Override
305
342
public void run () {
306
343
try {
307
- while (true ) {
308
- refresh ();
309
- Thread .sleep (timeout );
344
+ while (true ) {
345
+ try {
346
+ refresh ();
347
+ Thread .sleep (timeout );
348
+ } catch (ServiceUnavailableException e ) {
349
+ logger .error ("The billing database has been disabled."
350
+ + " To generate plots, please restart the service when"
351
+ + " the billing database is once again available" );
352
+ break ;
353
+ } catch (NoRouteToCellException e ) {
354
+ if (rate .tryAcquire ()) {
355
+ logger .warn ("No route to the billing service yet; "
356
+ + "retrying every 10 seconds" );
357
+ }
358
+ Thread .sleep (TimeUnit .SECONDS .toMillis (10 ));
359
+ }
310
360
}
311
361
} catch (InterruptedException interrupted ) {
312
362
logger .trace ("{} interrupted; exiting ..." , refresher );
313
- } catch (UndeclaredThrowableException ute ) {
314
- Throwable cause = ute .getCause ();
315
- if (cause instanceof ServiceUnavailableException ) {
316
- logger .error ("The billing database has been disabled. "
317
- + "To generate plots, please restart the service when "
318
- + "the billing database is once again available" );
319
- } else if (cause instanceof Error ) {
320
- throw ute ;
321
- }
322
-
323
- /*
324
- * if the service can't handle the client's requests, then we
325
- * back out here because there is nothing we can do
326
- */
327
- logger .error ("fatal billing request exception; "
328
- + "client loop is exiting" );
329
- logger .debug ("refresh" , ute );
330
363
}
331
364
}
332
365
@@ -361,7 +394,8 @@ public void shutDown() {
361
394
}
362
395
363
396
private void generatePlot (PlotType type , TimeFrame timeFrame ,
364
- String fileName , String title ) {
397
+ String fileName , String title ) throws ServiceUnavailableException ,
398
+ NoRouteToCellException {
365
399
List <TimeFrameHistogramData > data = load (type , timeFrame );
366
400
List <HistogramWrapper <?>> config = new ArrayList <>();
367
401
int i = 0 ;
@@ -452,4 +486,4 @@ private void synchronizeTimeFramePlotProperties() {
452
486
453
487
logger .debug ("plot properties are {}" , properties .toJavaProperties ());
454
488
}
455
- }
489
+ }
0 commit comments