// // Copyright 2019 SenX S.A.S. // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Affero General Public License as published // by the Free Software Foundation, version 3. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see // { 'name' 'senx/gts/first' 'desc' <' Return the first datapoint of a Geo Time Series '> 'sig' [ [ [ 'token:STRING' 'gts:GTS' 'offset:LONG' 'batchsize:LONG' ] REVERSE [ 'first:GTS' ] ] ] 'params' { 'token' 'Token to use for fetching data.' 'gts' 'Input Geo Time Series (possibly empty) of which we want the first tick.' 'offset' 'Shifting of timestamps during the initial search, the shorter this is, the longer it takes. This is expressed in time units, e.g. 30 d' 'batchsize' 'Number of ticks to retrieve at each FETCH operation. Use 1000 as a good compromise.' 'first' 'Geo Time Series™ containing only the first tick, or an empty GTS if the Geo Time Series is totally empty.' } } '.info' STORE <% !$.info INFO SAVE '.context' STORE [ 'TOKEN' 'GTS' 'OFFSET' 'BATCHSIZE' ] STORE // // Go backwards in time until we find no datapoint // $GTS TOSELECTOR 'SELECTOR' STORE NOW 'end' STORE $end 'prevend' STORE false 'done' STORE <% { 'token' $TOKEN 'selector' $SELECTOR 'end' $end 'count' $BATCHSIZE } FETCH 'gts' STORE // No datapoints, we went too much in the past $gts SIZE 0 == <% BREAK %> IFT // We fetched less than the batch size, so we know the first datapoint is the first we returned $gts 0 GET SIZE $BATCHSIZE < <% $gts 0 GET 1 SHRINK 'FIRST' STORE true 'done' STORE BREAK %> IFT // We fetch a full batch of datapoints // Determine next 'end' $gts 0 GET FIRSTTICK $end MIN 'end' STORE // Store the previous end timestamp so we can later walk our way forward in time $end 'prevend' STORE $end $OFFSET - 'end' STORE %> <% $done %> UNTIL $done NOT <% // // We now know the interval in which the last datapoint is // We will attempt to determine where exactly by doing a dichotomy between // $end and $prevend // $end $prevend + 2 / 'pivot' STORE <% { 'token' $TOKEN 'selector' $SELECTOR 'end' $pivot 'count' $BATCHSIZE } FETCH 'gts' STORE // If the FETCH returned no value, shift the pivot towards $prevend // and adjust 'end' $gts SIZE 0 == <% $pivot 'end' STORE $prevend $pivot + 2 / 'pivot' STORE CONTINUE %> IFT // If the FETCH returned a full batch of datapoints, shift the pivot towards $end, adjust prevend $gts 0 GET SIZE $BATCHSIZE == <% $gts 0 GET FIRSTTICK 'prevend' STORE $end $prevend + 2 / 'pivot' STORE CONTINUE %> IFT // We have less than a full batch, the first tick is the first one of the batch $gts 0 GET 1 SHRINK 'FIRST' STORE BREAK %> <% $end $pivot == $prevend $pivot == OR %> UNTIL %> IFT 'FIRST' DEFINED <% $FIRST %> <% $GTS CLONEEMPTY %> IFTE $.context RESTORE %>