| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.iotdb.db.metadata.mnode; |
| |
| import org.apache.iotdb.db.engine.trigger.executor.TriggerExecutor; |
| import org.apache.iotdb.db.exception.metadata.MetadataException; |
| import org.apache.iotdb.db.metadata.logfile.MLogWriter; |
| import org.apache.iotdb.db.metadata.template.Template; |
| import org.apache.iotdb.db.qp.physical.sys.MeasurementMNodePlan; |
| import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType; |
| import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; |
| import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding; |
| import org.apache.iotdb.tsfile.read.TimeValuePair; |
| import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema; |
| import org.apache.iotdb.tsfile.write.schema.MeasurementSchema; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.IOException; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** Represents an MNode which has a Measurement or Sensor attached to it. */ |
| public class MeasurementMNode extends MNode implements IMeasurementMNode { |
| |
| private static final Logger logger = LoggerFactory.getLogger(MeasurementMNode.class); |
| |
| private static final long serialVersionUID = -1199657856921206435L; |
| |
| /** measurement's Schema for one timeseries represented by current leaf node */ |
| private IMeasurementSchema schema; |
| |
| /** alias name of this measurement */ |
| private String alias; |
| |
| /** tag/attribute's start offset in tag file */ |
| private long offset = -1; |
| |
| /** last value cache */ |
| private TimeValuePair cachedLastValuePair = null; |
| |
| /** registered trigger */ |
| private TriggerExecutor triggerExecutor = null; |
| |
| /** @param alias alias of measurementName */ |
| public MeasurementMNode( |
| IMNode parent, |
| String measurementName, |
| String alias, |
| TSDataType dataType, |
| TSEncoding encoding, |
| CompressionType type, |
| Map<String, String> props) { |
| super(parent, measurementName); |
| this.schema = new MeasurementSchema(measurementName, dataType, encoding, type, props); |
| this.alias = alias; |
| } |
| |
| public MeasurementMNode( |
| IMNode parent, String measurementName, IMeasurementSchema schema, String alias) { |
| super(parent, measurementName); |
| this.schema = schema; |
| this.alias = alias; |
| } |
| |
| @Override |
| public IEntityMNode getParent() { |
| return (IEntityMNode) parent; |
| } |
| |
| @Override |
| public IMeasurementSchema getSchema() { |
| return schema; |
| } |
| |
| @Override |
| public void setSchema(IMeasurementSchema schema) { |
| this.schema = schema; |
| } |
| |
| @Override |
| public int getMeasurementMNodeCount() { |
| return 1; |
| } |
| |
| @Override |
| public int getMeasurementCount() { |
| return schema.getMeasurementCount(); |
| } |
| |
| /** |
| * get data type |
| * |
| * @param measurementId if it's a vector schema, we need sensor name of it |
| * @return measurement data type |
| */ |
| @Override |
| public TSDataType getDataType(String measurementId) { |
| if (schema instanceof MeasurementSchema) { |
| return schema.getType(); |
| } else { |
| int index = schema.getMeasurementIdColumnIndex(measurementId); |
| return schema.getValueTSDataTypeList().get(index); |
| } |
| } |
| |
| @Override |
| public long getOffset() { |
| return offset; |
| } |
| |
| @Override |
| public void setOffset(long offset) { |
| this.offset = offset; |
| } |
| |
| @Override |
| public String getAlias() { |
| return alias; |
| } |
| |
| @Override |
| public void setAlias(String alias) { |
| this.alias = alias; |
| } |
| |
| @Override |
| public TriggerExecutor getTriggerExecutor() { |
| return triggerExecutor; |
| } |
| |
| @Override |
| public void setTriggerExecutor(TriggerExecutor triggerExecutor) { |
| this.triggerExecutor = triggerExecutor; |
| } |
| |
| @Override |
| public TimeValuePair getCachedLast() { |
| return cachedLastValuePair; |
| } |
| |
| /** |
| * update last point cache |
| * |
| * @param timeValuePair last point |
| * @param highPriorityUpdate whether it's a high priority update |
| * @param latestFlushedTime latest flushed time |
| */ |
| @Override |
| public synchronized void updateCachedLast( |
| TimeValuePair timeValuePair, boolean highPriorityUpdate, Long latestFlushedTime) { |
| if (timeValuePair == null || timeValuePair.getValue() == null) { |
| return; |
| } |
| |
| if (cachedLastValuePair == null) { |
| // If no cached last, (1) a last query (2) an unseq insertion or (3) a seq insertion will |
| // update cache. |
| if (!highPriorityUpdate || latestFlushedTime <= timeValuePair.getTimestamp()) { |
| cachedLastValuePair = |
| new TimeValuePair(timeValuePair.getTimestamp(), timeValuePair.getValue()); |
| } |
| } else if (timeValuePair.getTimestamp() > cachedLastValuePair.getTimestamp() |
| || (timeValuePair.getTimestamp() == cachedLastValuePair.getTimestamp() |
| && highPriorityUpdate)) { |
| cachedLastValuePair.setTimestamp(timeValuePair.getTimestamp()); |
| cachedLastValuePair.setValue(timeValuePair.getValue()); |
| } |
| } |
| |
| @Override |
| public void resetCache() { |
| cachedLastValuePair = null; |
| } |
| |
| @Override |
| public void serializeTo(MLogWriter logWriter) throws IOException { |
| logWriter.serializeMeasurementMNode(this); |
| } |
| |
| /** |
| * deserialize MeasuremetMNode from string array |
| * |
| * @param nodeInfo node information array. For example: |
| * "2,s0,speed,2,2,1,year:2020;month:jan;,-1,0" representing: [0] nodeType [1] name [2] alias |
| * [3] TSDataType.ordinal() [4] TSEncoding.ordinal() [5] CompressionType.ordinal() [6] props |
| * [7] offset [8] children size |
| */ |
| public static IMeasurementMNode deserializeFrom(String[] nodeInfo) { |
| String name = nodeInfo[1]; |
| String alias = nodeInfo[2].equals("") ? null : nodeInfo[2]; |
| Map<String, String> props = new HashMap<>(); |
| if (!nodeInfo[6].equals("")) { |
| for (String propInfo : nodeInfo[6].split(";")) { |
| props.put(propInfo.split(":")[0], propInfo.split(":")[1]); |
| } |
| } |
| IMeasurementSchema schema = |
| new MeasurementSchema( |
| name, |
| Byte.parseByte(nodeInfo[3]), |
| Byte.parseByte(nodeInfo[4]), |
| Byte.parseByte(nodeInfo[5]), |
| props); |
| IMeasurementMNode node = new MeasurementMNode(null, name, schema, alias); |
| node.setOffset(Long.parseLong(nodeInfo[7])); |
| return node; |
| } |
| |
| /** deserialize MeasuremetMNode from MeasurementNodePlan */ |
| public static IMeasurementMNode deserializeFrom(MeasurementMNodePlan plan) { |
| IMeasurementMNode node = |
| new MeasurementMNode(null, plan.getName(), plan.getSchema(), plan.getAlias()); |
| node.setOffset(plan.getOffset()); |
| |
| return node; |
| } |
| |
| @Override |
| public String getFullPath() { |
| return concatFullPath(); |
| } |
| |
| @Override |
| public boolean hasChild(String name) { |
| return false; |
| } |
| |
| @Override |
| public IMNode getChild(String name) { |
| logger.warn("current node {} is a MeasurementMNode, can not get child {}", super.name, name); |
| throw new RuntimeException( |
| String.format( |
| "current node %s is a MeasurementMNode, can not get child %s", super.name, name)); |
| } |
| |
| @Override |
| public void addChild(String name, IMNode child) { |
| // Do nothing |
| } |
| |
| @Override |
| public IMNode addChild(IMNode child) { |
| return null; |
| } |
| |
| @Override |
| public void deleteChild(String name) { |
| // Do nothing |
| } |
| |
| @Override |
| public void replaceChild(String oldChildName, IMNode newChildNode) {} |
| |
| @Override |
| public IMNode getChildOfAlignedTimeseries(String name) throws MetadataException { |
| return null; |
| } |
| |
| @Override |
| public Map<String, IMNode> getChildren() { |
| return Collections.emptyMap(); |
| } |
| |
| @Override |
| public void setChildren(Map<String, IMNode> children) { |
| // Do nothing |
| } |
| |
| @Override |
| public Template getUpperTemplate() { |
| return parent.getUpperTemplate(); |
| } |
| |
| @Override |
| public Template getSchemaTemplate() { |
| logger.warn("current node {} is a MeasurementMNode, can not get Device Template", name); |
| throw new RuntimeException( |
| String.format("current node %s is a MeasurementMNode, can not get Device Template", name)); |
| } |
| |
| @Override |
| public void setSchemaTemplate(Template schemaTemplate) {} |
| |
| @Override |
| public boolean isMeasurement() { |
| return true; |
| } |
| } |