public void printStatistics() {
    for (StationMeta stationMeta : stationMetaMap.values()) {
      System.out.println(stationMeta.stationName);
      for (SensorMeta sensorMeta : getSensorMap(stationMeta).values()) {
        BTreeMap<Integer, ChunkMeta> sensorChunkMetaMap = getSensorChunkMetaMap(sensorMeta);
        int entryCount = 0;
        for (ChunkMeta chunkMeta : sensorChunkMetaMap.values()) {
          entryCount += chunkMeta.entryCount;
        }
        BTreeMap<Integer, Chunk> sensorChunkMap = getSensorChunkMap(sensorMeta);
        System.out.print(
            sensorMeta.sensorName
                + " "
                + sensorChunkMetaMap.size()
                + ";"
                + sensorChunkMap.size()
                + ":"
                + entryCount
                + "   ");
      }
      System.out.println();
    }

    for (String key : db.getAll().keySet()) {
      System.out.println(key);
    }
  }
  public void removeSensorData(String stationName, String sensorName, int start, int end) {
    SensorMeta sensorMeta = getSensorMeta(stationName, sensorName, false);
    if (sensorMeta == null) {
      log.info("no sensor: " + stationName + " " + sensorName + " ->  nothing removed");
      return;
    }
    BTreeMap<Integer, ChunkMeta> chunkMetaMap = getSensorChunkMetaMap(sensorMeta);
    BTreeMap<Integer, Chunk> chunkMap = getSensorChunkMap(sensorMeta);

    ChunkMeta[] allChunkMetas = chunkMetaMap.values().toArray(new ChunkMeta[0]); // proxy

    for (ChunkMeta chunkMeta : allChunkMetas) {
      if (start <= chunkMeta.firstTimestamp
          && chunkMeta.lastTimestamp <= end) { // remove full chunk
        removeChunk(chunkMetaMap, chunkMap, chunkMeta);
      } else if (start <= chunkMeta.lastTimestamp
          && chunkMeta.firstTimestamp <= end) { // partial data chunk remove
        Chunk oldChunk = chunkMap.get(chunkMeta.firstTimestamp);
        Chunk newChunk = removeIntervalInChunk(oldChunk, start, end);
        if (newChunk != null) {
          removeChunk(chunkMetaMap, chunkMap, chunkMeta);
          insertChunk(chunkMetaMap, chunkMap, newChunk);
          log.trace("chunk part reinserted");
        } else {
          log.error("chunk not removed (internal error): " + chunkMeta);
        }
      }
    }
  }
  /** delete all content in db */
  public void clear() {
    for (StationMeta stationMeta : stationMetaMap.values()) {
      BTreeMap<String, SensorMeta> sensorMap = getSensorMap(stationMeta);
      for (SensorMeta sensorMeta : sensorMap.values()) {
        /*BTreeMap<Integer, ChunkMeta> chunkMetaMap = getSensorChunkMetaMap(sensorMeta);
        chunkMetaMap.clear();
        BTreeMap<Integer, Chunk> chunkMap = getSensorChunkMap(sensorMeta);
        chunkMap.clear();*/
        db.delete(sensorMeta.db_name_sensor_chunkmeta_map);
        db.delete(sensorMeta.db_name_sensor_chunk_map);
      }
      // sensorMap.clear();
      db.delete(stationMeta.db_name_sensor_map);

      db.delete(stationMeta.db_name_sensor_time_series_mask_map);
    }
    stationMetaMap.clear();
    commit();
    compact();
  }
 public int[] getStationTimeInterval(String stationName) {
   throwNull(stationName);
   BTreeMap<String, SensorMeta> sensorMap = getSensorMap(stationName);
   if (sensorMap == null || sensorMap.isEmpty()) {
     return null;
   }
   int minTimestamp = Integer.MAX_VALUE;
   int maxTimestamp = Integer.MIN_VALUE;
   for (SensorMeta sensorMeta : sensorMap.values()) {
     int[] interval = getSensorTimeInterval(sensorMeta);
     if (interval != null) {
       if (interval[0] < minTimestamp) {
         minTimestamp = interval[0];
       }
       if (maxTimestamp < interval[1]) {
         maxTimestamp = interval[1];
       }
     }
   }
   if (minTimestamp == Integer.MAX_VALUE || maxTimestamp == Integer.MIN_VALUE) {
     return null;
   }
   return new int[] {minTimestamp, maxTimestamp};
 }