All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yamcs.parameterarchive.ParameterValueSegment Maven / Gradle / Ivy

There is a newer version: 5.10.9
Show newest version
package org.yamcs.parameterarchive;

import org.yamcs.parameter.BasicParameterValue;
import org.yamcs.parameter.Value;
import org.yamcs.parameter.ValueArray;
import org.yamcs.protobuf.Pvalue.ParameterStatus;
import org.yamcs.protobuf.Yamcs.Value.Type;
import org.yamcs.utils.PeekingIterator;
import org.yamcs.utils.SortedIntArray;
import org.yamcs.utils.TimeEncoding;

import static org.yamcs.parameterarchive.ParameterArchive.STORE_RAW_VALUES;

import java.util.NoSuchElementException;

/**
 * Stores parameter values for one parameter over a time range.
 * 

* It is composed of a time, engineering, raw and parameter status segments and possibly by a list of gaps; *

* The engineering, raw and parameter status contain only the data - gaps are not stored in the segment themselves (the * timeSegment has by definition no gap). *

* To convert from a position as used in the time segment to a position in the other segments, the gaps have to be taken * into account. Such conversion can naturally result in no value if the requested position is part of the gaps. *

* The time segment is shared with other objects of this class and is updated outside this class */ public class ParameterValueSegment { final int pid; final SortedTimeSegment timeSegment; // engValueSegment should not be null during buildup but maybe null during retrieval (if the retrieving of // engineering values is skipped) ValueSegment engValueSegment; private ValueSegment rawValueSegment; private ParameterStatusSegment parameterStatusSegment; // stores the indices (positions) of the gaps SortedIntArray gaps; public ParameterValueSegment(int pid, SortedTimeSegment timeSegment, ValueSegment engValueSegment, ValueSegment rawValueSegment, ParameterStatusSegment parameterStatusSegment, SortedIntArray gaps) { this.pid = pid; this.timeSegment = timeSegment; this.engValueSegment = engValueSegment; this.rawValueSegment = rawValueSegment; this.parameterStatusSegment = parameterStatusSegment; this.gaps = gaps; } /** * * Creates a new segment and insert one value. The value is used to determine the individual engineering/raw segment * types. All future values are expected to be the same type. *

* The length of the segment (number of parameters) is given by the timeSegment length. *

* If the length is greater than 1, then all other positions will be initialised with gaps. */ public ParameterValueSegment(int pid, SortedTimeSegment timeSegment, int pos, BasicParameterValue pv) { this.pid = pid; this.timeSegment = timeSegment; Value v = pv.getEngValue(); if (v != null) { engValueSegment = getNewSegment(v.getType()); } else { engValueSegment = null; } parameterStatusSegment = new ParameterStatusSegment(true); if (STORE_RAW_VALUES) { Value rawV = pv.getRawValue(); if (rawV != null) { rawValueSegment = getNewSegment(rawV.getType()); } else { rawValueSegment = null; } } else { rawValueSegment = null; } for (int i = 0; i < pos; i++) { insertGap(i); } insert(pos, pv); for (int i = pos + 1; i < timeSegment.size(); i++) { insertGap(i); } } public void insertGap(int pos) { if (gaps == null) { gaps = new SortedIntArray(); } else { // the position of all the indices following the pos have to increase by 1 gaps.addIfGreaterOrEqualThan(pos, 1); } gaps.insert(pos); } public void insert(int pos, BasicParameterValue pv) { if (pos == timeSegment.size()) { // fast path inserting data at the end, no need to care about gaps if (engValueSegment != null) { engValueSegment.add(pv.getEngValue()); } parameterStatusSegment.addParameterValue(pv); if (rawValueSegment != null) { rawValueSegment.add(pv.getRawValue()); } } else { if (gaps == null) { if (engValueSegment != null) { engValueSegment.insert(pos, pv.getEngValue()); } parameterStatusSegment.insertParameterValue(pos, pv); if (rawValueSegment != null) { rawValueSegment.insert(pos, pv.getRawValue()); } } else { int pos1; var idx = gaps.search(pos); if (idx < 0) { pos1 = pos + idx + 1; } else { pos1 = pos - idx; } if (engValueSegment != null) { engValueSegment.insert(pos1, pv.getEngValue()); } parameterStatusSegment.insertParameterValue(pos1, pv); if (rawValueSegment != null) { rawValueSegment.insert(pos1, pv.getRawValue()); } gaps.addIfGreaterOrEqualThan(pos, 1); } } } // returns the modified position after gaps are eliminated or -1 if the position corresponds to a gap private int gaplessPosition(int pos) { if (gaps == null) { return pos; } else { var idx = gaps.search(pos); if (idx < 0) { return pos + idx + 1; } else { return -1; } } } /** * returns the modified position after gaps are eliminated *

* if the position corresponds to a gap, return the next position or the segment size if the gap is at the end *

* it assumes gaps is non null */ int nextAfterGap(int pos) { var idx = gaps.search(pos); if (idx < 0) { return pos + idx + 1; } else { return pos - idx; } } /** * returns the modified position after gaps are eliminated *

* if the position corresponds to a gap, return the previous position or -1 if the gap is at the beginning *

* it assumes gaps is non null */ int previousBeforeGap(int pos) { var idx = gaps.search(pos); if (idx < 0) { return pos + idx + 1; } else { int x = pos - idx - 1; return x < 0 ? -1 : x; } } /** *

* Optimise for writing to archive */ public void consolidate() { parameterStatusSegment.consolidate(); if (engValueSegment != null) { engValueSegment.consolidate(); } if (STORE_RAW_VALUES) { if (rawValueSegment != null) { // the raw values will only be stored if they are different than the engineering values if (rawValueSegment.equals(engValueSegment)) { rawValueSegment = null; } else { rawValueSegment.consolidate(); } } } } public ParameterValueArray getRange(int posStart, int posStop, boolean ascending, boolean retrieveParameterStatus) { long[] timestamps; if (gaps == null) { timestamps = timeSegment.getRange(posStart, posStop, ascending); } else { timestamps = timeSegment.getRangeWithGaps(posStart, posStop, ascending, gaps); if (ascending) { posStart = nextAfterGap(posStart); posStop = nextAfterGap(posStop); } else { posStart = previousBeforeGap(posStart); posStop = previousBeforeGap(posStop); } } if (posStart >= posStop) {// only gaps return null; } ValueArray engValues = null; if (engValueSegment != null) { engValues = engValueSegment.getRange(posStart, posStop, ascending); } ValueArray rawValues = null; if (rawValueSegment == engValueSegment) { rawValues = engValues; } else if (rawValueSegment != null) { rawValues = rawValueSegment.getRange(posStart, posStop, ascending); } ParameterStatus[] paramStatus = null; if (retrieveParameterStatus) { paramStatus = parameterStatusSegment.getRangeArray(posStart, posStop, ascending); } return new ParameterValueArray(timestamps, engValues, rawValues, paramStatus); } public long getSegmentStart() { return timeSegment.getSegmentStart(); } public long getSegmentEnd() { return timeSegment.getSegmentEnd(); } public int numGaps() { return gaps == null ? 0 : gaps.size(); } public int numValues() { int numGaps = gaps == null ? 0 : gaps.size(); return timeSegment.size() - numGaps; } public BaseSegment getConsolidatedEngValueSegment() { return (BaseSegment) engValueSegment; } public BaseSegment getConsolidatedRawValueSegment() { return (BaseSegment) rawValueSegment; } public BaseSegment getConsolidatedParmeterStatusSegment() { return (BaseSegment) parameterStatusSegment; } static private ValueSegment getNewSegment(Type type) { switch (type) { case BINARY: return new BinaryValueSegment(true); case STRING: case ENUMERATED: return new StringValueSegment(true); case SINT32: return new IntValueSegment(true); case UINT32: return new IntValueSegment(false); case FLOAT: return new FloatValueSegment(); case SINT64: case UINT64: case TIMESTAMP: // intentional fall through return new LongValueSegment(type); case DOUBLE: return new DoubleValueSegment(); case BOOLEAN: return new BooleanValueSegment(); default: throw new IllegalStateException("Unknown type " + type); } } public TimedValue getTimedValue(int pos) { pos = gaplessPosition(pos); if (pos < 0) { return null; } long t = timeSegment.getTime(pos); Value ev = (engValueSegment == null) ? null : engValueSegment.getValue(pos); Value rv = (rawValueSegment == null) ? null : rawValueSegment.getValue(pos); ParameterStatus ps = (parameterStatusSegment == null) ? null : parameterStatusSegment.get(pos); return new TimedValue(t, ev, rv, ps); } public Value getEngValue(int pos) { pos = gaplessPosition(pos); if (pos < 0) { return null; } return engValueSegment.getValue(pos); } public Value getRawValue(int pos) { pos = gaplessPosition(pos); if (pos < 0) { return null; } return rawValueSegment.getValue(pos); } public SortedIntArray getGaps() { return gaps; } public PeekingIterator newAscendingIterator(long t0) { return new AscendingIterator(t0); } public PeekingIterator newDescendingIterator(long t0) { return new DescendingIterator(t0); } /** * In rare circumstances, a segment read from the archive has to be modified. *

* This method updates the object such that it can be modified */ public void makeWritable() { parameterStatusSegment.makeWritable(); engValueSegment.makeWritable(); if (rawValueSegment != null) { rawValueSegment.makeWritable(); } } @Override public String toString() { return "ParameterValueSegment[size: " + timeSegment.size() + ", start: " + TimeEncoding.toString(getSegmentStart()) + ", end: " + TimeEncoding.toString(getSegmentEnd()) + "]"; } class AscendingIterator implements PeekingIterator { private int idxT; private int idxV; private int idxG; private TimedValue currentValue = null; public AscendingIterator(long t0) { idxT = timeSegment.lowerBound(t0); if (gaps == null) { idxV = idxT; } else { idxG = gaps.search(idxT); if (idxG < 0) { idxG = -(idxG + 1); } idxV = idxT - idxG; } next(); } public boolean isValid() { return currentValue != null; } public TimedValue value() { if (!isValid()) { throw new NoSuchElementException(); } return currentValue; } public void next() { while (gaps != null && idxG < gaps.size() && idxT == gaps.get(idxG)) { idxT++; idxG++; } if (idxV < numValues()) { Value ev = (engValueSegment == null) ? null : engValueSegment.getValue(idxV); Value rv = (rawValueSegment == null) ? null : rawValueSegment.getValue(idxV); ParameterStatus ps = (parameterStatusSegment == null) ? null : parameterStatusSegment.get(idxV); currentValue = new TimedValue(timeSegment.getTime(idxT), ev, rv, ps); idxT++; idxV++; } else { currentValue = null; } } } class DescendingIterator implements PeekingIterator { private int idxT; private int idxV; private int idxG; private TimedValue currentValue = null; public DescendingIterator(long t0) { idxT = timeSegment.higherBound(t0); if (gaps == null) { idxV = idxT; } else { idxG = gaps.search(idxT); if (idxG < 0) { idxG = -(idxG + 2); } idxV = idxT - idxG - 1; } next(); } public boolean isValid() { return currentValue != null; } public TimedValue value() { if (!isValid()) { throw new NoSuchElementException(); } return currentValue; } public void next() { while (gaps != null && idxG >= 0 && idxT == gaps.get(idxG)) { idxT--; idxG--; } if (idxT >= 0 && idxV >= 0) { Value ev = (engValueSegment == null) ? null : engValueSegment.getValue(idxV); Value rv = (rawValueSegment == null) ? null : rawValueSegment.getValue(idxV); ParameterStatus ps = (parameterStatusSegment == null) ? null : parameterStatusSegment.get(idxV); currentValue = new TimedValue(timeSegment.getTime(idxT), ev, rv, ps); idxT--; idxV--; } else { currentValue = null; } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy