Back to Doris

fe-foundation Module Design Document

fe/fe-foundation/DESIGN.md

4.1.18.2 KB
Original Source

fe-foundation Module Design Document

1. Background & Motivation

The existing fe-common module has accumulated heavy dependencies over time (Guava, Hadoop, Trino, ANTLR, Alibaba MaxCompute SDK, etc.), making it unsuitable as a lightweight shared library for the plugin/SPI ecosystem. When SPI plugin authors depend on fe-common, they are forced to pull in dozens of transitive dependencies that have nothing to do with their plugin logic.

We need a zero-dependency foundation module that sits below fe-common and fe-extension-spi in the dependency hierarchy, providing only the most essential, general-purpose utilities that any module — including SPI plugins — can safely depend on.

2. Naming Decision

CandidateVerdict
fe-foundationChosen. Clear "below-common" semantics. No ambiguity with existing modules.
fe-baseToo generic; widely used in other contexts.
fe-essentialsGood semantics but verbose.
fe-primitivesImplies primitive types; misleading.
fe-toolkitIndustry convention maps "toolkit" to heavier helper libs (e.g., Trino).
fe-kernelConflicts with database "kernel" terminology.

Industry references:

  • Trino: trino-spi (zero-dep contract) + lib/trino-plugin-toolkit (optional helpers)
  • Flink: flink-annotations (lightest) → flink-core-apiflink-core
  • Iceberg: common/ (pure utilities) → api/ (interfaces) → core/ (implementation)
  • SeaTunnel: seatunnel-common (utilities) + seatunnel-api (SPI)

3. Module Positioning

fe-foundation          ← Zero third-party dependencies. Pure JDK utilities.
    │
    ├── fe-extension-spi       ← Plugin contracts (Plugin, PluginFactory, PluginContext)
    │       │
    │       └── fe-extension-loader    ← Plugin classloading & discovery
    │
    ├── fe-common              ← Heavier shared code (Gson, Guava, Hadoop, etc.)
    │
    └── fe-core                ← Main FE module (optimizer, catalog, transaction)

Key principle: fe-foundation has ZERO compile-scope third-party dependencies. Only JDK.

4. Admission Criteria

A class qualifies for fe-foundation if it meets ALL of:

  1. Zero third-party runtime dependencies — only java.* imports
  2. No coupling to Doris business logic — no references to catalog, optimizer, planner, etc.
  3. General-purpose — useful across multiple modules (SPI plugins, fe-common, fe-core, etc.)
  4. Stable API — unlikely to change frequently

5. Package Structure

org.apache.doris.foundation/
├── property/
│   ├── ConnectorProperty.java           # @annotation: marks config fields
│   ├── ConnectorPropertiesUtils.java    # Reflection-based KV → Bean binder
│   ├── StoragePropertiesException.java  # Property-related RuntimeException
│   └── ParamRules.java                  # Fluent parameter validation DSL
├── type/
│   └── ResultOr.java                    # Rust-style Result<T, E> type
├── format/
│   └── FormatOptions.java               # Immutable data formatting config
└── util/
    ├── BitUtil.java                     # Bit manipulation helpers
    ├── ByteBufferUtil.java              # Unsigned ByteBuffer reads
    ├── SerializationUtils.java          # Deep clone via Java serialization
    └── PathUtils.java                   # URI path comparison utilities

6. Classes Included (First Iteration)

6.1 Property Framework (from fe-core)

ClassOriginal LocationExternal DepsDescription
ConnectorPropertyo.a.d.datasource.propertyNoneRuntime annotation for connector config fields
ConnectorPropertiesUtilso.a.d.datasource.propertyNone (Guava/commons-lang3 removed)Reflection-based KV→Bean binding
ParamRuleso.a.d.datasource.propertyNoneFluent validation DSL with chained rules
StoragePropertiesExceptiono.a.d.datasource.property.storage.exceptionNoneRuntimeException for property errors

6.2 Type Utilities (from fe-common)

ClassOriginal LocationExternal DepsDescription
ResultOr<T,E>o.a.d.commonNoneSuccess-or-error result type

6.3 Format Utilities (from fe-common)

ClassOriginal LocationExternal DepsDescription
FormatOptionso.a.d.commonNoneImmutable formatting configuration

6.4 General Utilities (from fe-core)

ClassOriginal LocationExternal DepsDescription
BitUtilo.a.d.common.utilNonelog2, power-of-2 rounding
ByteBufferUtilo.a.d.common.utilNoneUnsigned byte buffer reads
SerializationUtilso.a.d.common.utilNoneDeep clone via serialization
PathUtilso.a.d.common.utilNoneURI path comparison with S3 handling

7. Classes NOT Included (and Why)

ClassReason
Pair, TripleDepend on @SerializedName (Gson) for persistence. Moving would require adding Gson or breaking persistence compatibility.
Writable, Codec, CountingDataOutputStream, DataInputBuffer, DataOutputBuffer, etc.Deeply embedded in the persistence layer (194+ importers for Writable). High-risk migration better done in a separate phase.
CloudCredentialDepends on commons-lang3. Could be migrated after trivial refactoring.
GZIPUtils, EnvUtilsDepend on commons-io / Guava. Could be migrated after trivial refactoring.

8. Serialization Safety Analysis

All 10 classes are SAFE to move (package rename):

  • None implement java.io.Serializable (except StoragePropertiesException via Throwable, but it is never serialized to disk)
  • None are registered in RuntimeTypeAdapterFactory (no class name stored in JSON)
  • None have serialVersionUID
  • All are either annotations, static utility classes, or transient runtime objects
  • No class name is stored in any editlog, metadata image, or checkpoint

9. Migration Strategy

Phase 1 (This PR): Backward-Compatible Migration

  1. Create fe-foundation module with zero dependencies
  2. Copy classes to new org.apache.doris.foundation.* packages
  3. In original locations, replace class bodies with extends/delegation to the foundation class:
    java
    // fe-core: org.apache.doris.datasource.property.ParamRules
    // Now just re-exports the foundation class
    package org.apache.doris.datasource.property;
    public class ParamRules extends org.apache.doris.foundation.property.ParamRules {}
    
  4. No existing code needs to change import statements
  5. New code should prefer importing from org.apache.doris.foundation.*

Phase 2 (Future): Gradually update imports across the codebase

  • Update import statements in fe-core to use foundation packages directly
  • Deprecate and eventually remove the re-export shims
  • Migrate more classes from fe-common (IO utilities, Pair/Triple after decoupling Gson)

10. Build Configuration

xml
<!-- fe-foundation/pom.xml -->
<artifactId>fe-foundation</artifactId>
<packaging>jar</packaging>
<name>Doris FE Foundation</name>
<description>Zero-dependency foundation utilities for Doris FE modules and SPI plugins</description>

<dependencies>
    <!-- Intentionally empty. This module has ZERO third-party dependencies. -->
</dependencies>

11. Dependency Graph After Migration

fe-foundation (0 deps)
    ↑
    ├── fe-extension-spi (depends on fe-foundation)
    │       ↑
    │       └── fe-extension-loader
    │
    ├── fe-common (depends on fe-foundation + Guava + Gson + Hadoop + ...)
    │       ↑
    │       └── fe-core
    │
    └── fe-core (depends on fe-foundation + fe-common + ...)