爱吃芒果

Java日志实战

主要其实是学习Java日志通关系列文章,大佬太强了

/posts/java-log-in-practice/image-20250722145042812.png

日志发展到今天,被抽象成了三层,接口层、实现层、适配层。

  • 接口层:或者叫日志门面(facade),就是interface,只定义接口,等别人实现
  • 实现层:真正干活的,能够把日志内存记录下来的工具,但请注意它不是上面接口实现,因为它不感知也不直接实现接口,仅仅是独立的实现
  • 适配层:一般称为adapter,因为接口层和适配层并非都出自一家之手,它们之间无法直接匹配

适配层有可以分为绑定(binding)和桥接(bridging)两种能力:

Presto数据过滤和投影

简单拉取数据查询的实现原理

SELECT ss_item_sk, ss_sales_price
FROM store_sales;

执行计划的生成和优化

初始逻辑执行计划

TableScan节点:负责从数据源连接器拉取数据

Output节点:逻辑执行计划的根节点,表示输出计算结果,其自身没有计算逻辑

public class TableScanNode
        extends PlanNode
{
  	// TableHandle表示的是与当前TableScanNode对应的是数据源存储中的那个类
    private final TableHandle table;
  	// outputSymbols: TableScanNode输出的symbols列表,在Presto中使用Symbol表示要输出哪些列
    private final List<Symbol> outputSymbols;
  	// assignments:对于outputSymbols中的每个Symbol,明确其来源于数据源Connector的那个Column(用ColumnHandle表示)
    private final Map<Symbol, ColumnHandle> assignments; // symbol -> column

    private final TupleDomain<ColumnHandle> enforcedConstraint;
    private final boolean forDelete;

查询执行时,只要将TableHandle、ColumnHandl交给数据源连接器,它就知道拉取那些表、哪些列的数据,这是一个基本抽象,在考虑到各种下推优化时,这两个概念将发挥更大的作用

文件锁

在ehcache3中看到ehcache3通过文件锁来保证对目录的唯一拥有

public class DefaultLocalPersistenceService implements LocalPersistenceService {

  private static final Logger LOGGER = LoggerFactory.getLogger(DefaultLocalPersistenceService.class);

  private final File rootDirectory;
  private final File lockFile;

  private FileLock lock;
  private RandomAccessFile rw;
  private boolean started;

  /**
   * Creates a new service instance using the provided configuration.
   *
   * @param persistenceConfiguration the configuration to use
   */
  public DefaultLocalPersistenceService(final DefaultPersistenceConfiguration persistenceConfiguration) {
    if(persistenceConfiguration != null) {
      rootDirectory = persistenceConfiguration.getRootDirectory();
    } else {
      throw new NullPointerException("DefaultPersistenceConfiguration cannot be null");
    }
    lockFile = new File(rootDirectory, ".lock");
  }


  private void internalStart() {
    if (!started) {
      createLocationIfRequiredAndVerify(rootDirectory);
      try {
        rw = new RandomAccessFile(lockFile, "rw");
      } catch (FileNotFoundException e) {
        // should not happen normally since we checked that everything is fine right above
        throw new RuntimeException(e);
      }
      try {
        lock = rw.getChannel().tryLock();
      } catch (OverlappingFileLockException e) {
        throw new RuntimeException("Persistence directory already locked by this process: " + rootDirectory.getAbsolutePath(), e);
      } catch (Exception e) {
        try {
          rw.close();
        } catch (IOException e1) {
          // ignore silently
        }
        throw new RuntimeException("Persistence directory couldn't be locked: " + rootDirectory.getAbsolutePath(), e);
      }
      if (lock == null) {
        throw new RuntimeException("Persistence directory already locked by another process: " + rootDirectory.getAbsolutePath());
      }
      started = true;
      LOGGER.debug("RootDirectory Locked");
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public synchronized void stop() {
    if (started) {
      try {
        lock.release();
        // Closing RandomAccessFile so that files gets deleted on windows and
        // org.ehcache.internal.persistence.DefaultLocalPersistenceServiceTest.testLocksDirectoryAndUnlocks()
        // passes on windows
        rw.close();
        try {
          Files.delete(lockFile.toPath());
        } catch (IOException e) {
          LOGGER.debug("Lock file was not deleted {}.", lockFile.getPath());
        }
      } catch (IOException e) {
        throw new RuntimeException("Couldn't unlock rootDir: " + rootDirectory.getAbsolutePath(), e);
      }
      started = false;
      LOGGER.debug("RootDirectory Unlocked");
    }
  }

java Size Of Engine

ehcache3提供了限制缓存容量的选择,如果堆上存储的容量超过了指定的大小,则会驱逐缓存中的元素,直到有空间可以容纳为止。

自己实现的sizeOfEngine应该实现ehcache3提供的引擎接口。