code: /*
   * 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.skywalking.oap.server.core.profiling.ebpf.storage;
  
  import com.google.common.base.Charsets;
  import com.google.common.hash.Hashing;
  import lombok.Data;
  import org.apache.skywalking.oap.server.core.analysis.Stream;
  import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
  import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor;
  import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
  import org.apache.skywalking.oap.server.core.storage.StorageID;
  import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
  import org.apache.skywalking.oap.server.core.storage.annotation.Column;
  import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
  import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
  import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
  
  import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.EBPF_PROFILING_TASK;
  
  /**
   * eBPF Profiling Task is the user create it from the UI side
   */
  @Data
  @ScopeDeclaration(id = EBPF_PROFILING_TASK, name = "EBPFProfilingTask")
  @Stream(name = EBPFProfilingTaskRecord.INDEX_NAME, scopeId = EBPF_PROFILING_TASK,
      builder = EBPFProfilingTaskRecord.Builder.class, processor = NoneStreamProcessor.class)
  @BanyanDB.TimestampColumn(EBPFProfilingTaskRecord.CREATE_TIME)
  public class EBPFProfilingTaskRecord extends NoneStream {
      public static final String INDEX_NAME = "ebpf_profiling_task";
      public static final String LOGICAL_ID = "logical_id";
      public static final String SERVICE_ID = "service_id";
      public static final String PROCESS_LABELS_JSON = "process_labels_json";
      public static final String INSTANCE_ID = "instance_id";
      public static final String START_TIME = "start_time";
      public static final String TRIGGER_TYPE = "trigger_type";
      public static final String FIXED_TRIGGER_DURATION = "fixed_trigger_duration";
      public static final String TARGET_TYPE = "target_type";
      public static final String CREATE_TIME = "create_time";
      public static final String LAST_UPDATE_TIME = "last_update_time";
      public static final String EXTENSION_CONFIG_JSON = "extension_config_json";
      public static final String CONTINUOUS_PROFILING_JSON = "continuous_profiling_json";
  
      public static final int PROCESS_LABELS_JSON_MAX_LENGTH = 1000;
      public static final int EXTENSION_CONFIG_JSON_MAX_LENGTH = 1000;
      public static final int CONTINOUS_PROFILING_JSON_MAX_LENGTH = 1000;
  
      @Column(name = LOGICAL_ID)
      private String logicalId;
      @Column(name = SERVICE_ID)
      @BanyanDB.SeriesID(index = 0)
      private String serviceId;
      @Column(name = PROCESS_LABELS_JSON, length = PROCESS_LABELS_JSON_MAX_LENGTH)
      private String processLabelsJson;
      @Column(name = INSTANCE_ID, length = 512)
      private String instanceId;
      @Column(name = START_TIME)
      private long startTime;
      @Column(name = TRIGGER_TYPE)
      private int triggerType = EBPFProfilingTriggerType.UNKNOWN.value();
      @Column(name = FIXED_TRIGGER_DURATION)
      private long fixedTriggerDuration;
      @Column(name = TARGET_TYPE)
      private int targetType = EBPFProfilingTargetType.UNKNOWN.value();
      @Column(name = CREATE_TIME)
      private long createTime;
      @Column(name = LAST_UPDATE_TIME)
      private long lastUpdateTime;
      @Column(name = EXTENSION_CONFIG_JSON, length = EXTENSION_CONFIG_JSON_MAX_LENGTH, storageOnly = true)
      private String extensionConfigJson;
      @Column(name = CONTINUOUS_PROFILING_JSON, length = CONTINOUS_PROFILING_JSON_MAX_LENGTH, storageOnly = true)
      private String continuousProfilingJson;
  
      @Override
      public StorageID id() {
          return new StorageID().appendMutant(
              new String[] {
                  LOGICAL_ID,
                  CREATE_TIME
              },
              Hashing.sha256().newHasher()
                     .putString(logicalId, Charsets.UTF_8)
                     .putLong(createTime)
                     .hash().toString()
          );
      }
  
      /**
       * Generate the logical id and put it into record
       */
      public void generateLogicalId() {
          this.logicalId = Hashing.sha256().newHasher()
                                  .putString(serviceId, Charsets.UTF_8)
                                  .putString(processLabelsJson, Charsets.UTF_8)
                                  .putLong(startTime)
                                  .hash().toString();
      }
  
      /**
       * combine the same task
       * @param task have same {@link #logicalId}
       */
      public EBPFProfilingTaskRecord combine(EBPFProfilingTaskRecord task) {
          if (task.getFixedTriggerDuration() > this.getFixedTriggerDuration()) {
              this.setFixedTriggerDuration(task.getFixedTriggerDuration());
          }
          if (task.getLastUpdateTime() > this.getLastUpdateTime()) {
              this.setLastUpdateTime(task.getLastUpdateTime());
          }
          return this;
      }
  
      public static class Builder implements StorageBuilder<EBPFProfilingTaskRecord> {
  
          @Override
          public EBPFProfilingTaskRecord storage2Entity(final Convert2Entity converter) {
              final EBPFProfilingTaskRecord record = new EBPFProfilingTaskRecord();
              record.setLogicalId((String) converter.get(LOGICAL_ID));
              record.setServiceId((String) converter.get(SERVICE_ID));
              record.setProcessLabelsJson((String) converter.get(PROCESS_LABELS_JSON));
              record.setInstanceId((String) converter.get(INSTANCE_ID));
              record.setTriggerType(((Number) converter.get(TRIGGER_TYPE)).intValue());
              record.setStartTime(((Number) converter.get(START_TIME)).longValue());
              record.setFixedTriggerDuration(((Number) converter.get(FIXED_TRIGGER_DURATION)).longValue());
              record.setTargetType(((Number) converter.get(TARGET_TYPE)).intValue());
              record.setCreateTime(((Number) converter.get(CREATE_TIME)).longValue());
              record.setLastUpdateTime(((Number) converter.get(LAST_UPDATE_TIME)).longValue());
              record.setTimeBucket(((Number) converter.get(TIME_BUCKET)).longValue());
              record.setExtensionConfigJson((String) converter.get(EXTENSION_CONFIG_JSON));
              record.setContinuousProfilingJson((String) converter.get(CONTINUOUS_PROFILING_JSON));
              return record;
          }
  
          @Override
          public void entity2Storage(final EBPFProfilingTaskRecord storageData, final Convert2Storage converter) {
              converter.accept(LOGICAL_ID, storageData.getLogicalId());
              converter.accept(SERVICE_ID, storageData.getServiceId());
              converter.accept(PROCESS_LABELS_JSON, storageData.getProcessLabelsJson());
              converter.accept(INSTANCE_ID, storageData.getInstanceId());
              converter.accept(TRIGGER_TYPE, storageData.getTriggerType());
              converter.accept(START_TIME, storageData.getStartTime());
              converter.accept(FIXED_TRIGGER_DURATION, storageData.getFixedTriggerDuration());
              converter.accept(TARGET_TYPE, storageData.getTargetType());
              converter.accept(CREATE_TIME, storageData.getCreateTime());
              converter.accept(LAST_UPDATE_TIME, storageData.getLastUpdateTime());
              converter.accept(TIME_BUCKET, storageData.getTimeBucket());
              converter.accept(EXTENSION_CONFIG_JSON, storageData.getExtensionConfigJson());
              converter.accept(CONTINUOUS_PROFILING_JSON, storageData.getContinuousProfilingJson());
          }
      }
  }
  