class Pocolog::StreamIndex

This file contains the index of a data stream.

Through this index it is possible to have an O(1) acess to the data position with an given sample number.

Time base access has a complexity of O(log N)

Attributes

base_time[R]
time_to_position_map[R]

Public Class Methods

new() click to toggle source
# File lib/pocolog/stream_index.rb, line 31
def initialize
    # The index holds three arrays, which associate
    # the position number of a sample in a stream
    # with the file, file position and time of the sample
    #
    # The file is encoded as an index value (rio) since
    # pocolog accepts multifile log streams
    #
    @nr_to_position_map = Array.new()
    @base_time = nil
    @time_to_position_map = Array.new()
    @nr_to_rio = Array.new()
end
time_from_internal(time, base_time) click to toggle source
# File lib/pocolog/stream_index.rb, line 64
def self.time_from_internal(time, base_time)
    time = time + base_time
    Time.at(time / 1_000_000, time % 1_000_000)
end
time_to_internal(time, base_time) click to toggle source
# File lib/pocolog/stream_index.rb, line 69
def self.time_to_internal(time, base_time)
    internal = time.tv_sec * 1_000_000 + time.tv_usec
    internal - base_time
end

Public Instance Methods

add_sample_to_index(rio, pos, time) click to toggle source

adds a given sample header (and thus the sample) to the index

# File lib/pocolog/stream_index.rb, line 47
def add_sample_to_index(rio, pos, time)
    #store the posiiton of the header of the data sample
    @nr_to_rio << rio
    @nr_to_position_map << pos 
    internal_time = time.tv_sec * 1_000_000 + time.tv_usec
    @base_time ||= internal_time
    @time_to_position_map << [(internal_time - @base_time), time_to_position_map.size]
end
base_time=(value) click to toggle source
# File lib/pocolog/stream_index.rb, line 17
def base_time=(value)
    @base_time ||= value
    offset = @base_time - value
    return if offset == 0
    @time_to_position_map = time_to_position_map.map do |t, i|
        [t + offset, i]
    end
    @base_time = value
end
file_position_by_sample_number(sample_nr) click to toggle source

Expects the number of the sample that needs to be accessed and returns the position of the sample in the file

# File lib/pocolog/stream_index.rb, line 94
def file_position_by_sample_number(sample_nr)
    return @nr_to_rio[sample_nr], @nr_to_position_map[sample_nr]
end
internal_time_by_sample_number(sample_nr) click to toggle source
# File lib/pocolog/stream_index.rb, line 98
def internal_time_by_sample_number(sample_nr)
    if(sample_nr < 0 || sample_nr >= size)
        raise ArgumentError, "#{sample_nr} out of bounds"
    end
    @time_to_position_map[sample_nr].first
end
marshal_dump() click to toggle source
# File lib/pocolog/stream_index.rb, line 111
def marshal_dump
    [@nr_to_rio.pack("n*"),
     @nr_to_position_map.pack("Q>*"),
     @base_time,
     @time_to_position_map.map(&:first).pack("Q>*")]
end
marshal_load(info) click to toggle source
# File lib/pocolog/stream_index.rb, line 118
def marshal_load(info)
    if info.size == 4
        nr_to_rio, nr_to_position_map, base_time, time_to_position_map = *info
        @nr_to_rio = nr_to_rio.unpack("n*")
        @nr_to_position_map = nr_to_position_map.unpack("Q>*")
        @base_time = base_time
        @time_to_position_map = time_to_position_map.unpack("Q>*").each_with_index.map do |time, i|
            [time, i]
        end
        return
    end

    nr_to_rio, nr_to_position_map, time_to_position_map = *info
    if nr_to_rio.respond_to?(:to_str)
        @nr_to_rio = nr_to_rio.unpack("n*")
        @nr_to_position_map = nr_to_position_map.unpack("Q>*")
        time_to_position_map = time_to_position_map.unpack("Q>*")
        if time_to_position_map.empty?
        else
            # Old-new-style :( [tv_sec, tv_usec]
            base, _ = time_to_position_map.first
            @base_time = base
            @time_to_position_map = time_to_position_map.each_slice(2).map { |sec, usec| (sec - base) * 1_000_000 + usec }
        end
    else
        Pocolog.warn "found an old-format index. Consider deleting all your index files to upgrade to a newer format"
        @nr_to_rio = nr_to_rio
        @nr_to_position_map = nr_to_position_map
        @time_to_position_map = time_to_position_map.map do |tv_sec, tv_usec|
            Time.at(tv_sec, tv_usec)
        end
    end
end
sample_number_by_internal_time(sample_time) click to toggle source

Returns the sample number of the first sample whose time is not before the given time

@param [Integer]

# File lib/pocolog/stream_index.rb, line 87
def sample_number_by_internal_time(sample_time)
    _, idx = @time_to_position_map.bsearch { |t, _| t >= sample_time }
    idx || size
end
sample_number_by_time(sample_time) click to toggle source

Returns the sample number of the first sample whose time is not before the given time

@param [Time]

# File lib/pocolog/stream_index.rb, line 78
def sample_number_by_time(sample_time)
    sample_time = StreamIndex.time_to_internal(sample_time, base_time)
    sample_number_by_internal_time(sample_time)
end
sane?() click to toggle source

sanity check for the index, which gets called after marshalling, to see if the index needs rebuilding

# File lib/pocolog/stream_index.rb, line 58
def sane?
    @nr_to_rio && @nr_to_position_map && @time_to_position_map &&
    @nr_to_rio.size == @nr_to_position_map.size &&
    @nr_to_rio.size == @time_to_position_map.size
end
size() click to toggle source
# File lib/pocolog/stream_index.rb, line 27
def size
    @time_to_position_map.size
end
time_by_sample_number(sample_nr) click to toggle source

expects a sample nr and returns the time of the sample

# File lib/pocolog/stream_index.rb, line 107
def time_by_sample_number(sample_nr)
    StreamIndex.time_from_internal(internal_time_by_sample_number(sample_nr), base_time)
end