Andrey Yarovoy created HDDS-17714:
-------------------------------------

             Summary: OFS getFileStatus should not refresh pipelines or return 
block locations
                 Key: HDDS-17714
                 URL: https://issues.apache.org/jira/browse/HDDS-17714
             Project: Apache Ozone
          Issue Type: Improvement
          Components: Ozone Filesystem
            Reporter: Andrey Yarovoy


*Description*

`BasicRootedOzoneFileSystem.getFileStatus` sends `GetFileStatus` with 
`headOp=false`. For a file, OM then:
- calls `refresh(fileKeyInfo)`, which looks up every block's container pipeline 
(`KeyManagerImpl.getOzoneFileStatusFSO`);
- optionally sorts the datanodes;
- returns the full `KeyLocationList`.

The client parses it (`OmKeyInfo.getFromProtobuf` → 
`OmKeyLocationInfo.getFromProtobuf` streams), builds a `BlockLocation[]`, and 
returns a
`LocatedFileStatus`.

HDFS `getFileStatus` returns no block locations; callers that need them call 
`getFileBlockLocations` or `listLocatedStatus`. Most
`getFileStatus` callers use only length, type, mtime and owner. HBase is the 
extreme case. Every `StoreScanner.trySwitchToStreamRead`
reopens each store file, and `StoreFileInfo.createReaderContext` calls 
`fs.getFileStatus(path)` only for `getLen()`.

*Follow-up to HDDS-15678 / HDDS-15877*

- **HDDS-15678** built the server side. With `headOp=true`, OM skips 
`refresh`/`sortDatanodes`, and
`OzoneManagerRequestHandler.getOzoneFileStatus` clears `KeyLocationList` from 
the response. On the client it switched ofs
`isFile`/`isDirectory` to head ops.
- **HDDS-15877** did the same for o3fs and the remaining *type-only* callers 
(trash roots, shell `DeleteKeyHandler`).
- Both deliberately left the public `FileSystem.getFileStatus(Path)` on 
`headOp=false`, because its result is a `LocatedFileStatus` that
`getFileBlockLocations(FileStatus)` reads. That is the call HBase makes on 
every store-file reopen, and still the call that pays the refresh and
returns all block locations.

This Jira finishes the job for `getFileStatus(Path)`. It returns a plain 
`FileStatus` (like HDFS), and `getFileBlockLocations` fetches the
locations only when they are actually requested.

*Evidence (HBase YCSB on EC, RegionServer async-profiler, 6×60s per arm)*

- `getFileStatus` is 12.5–14.6% of busy RS handler time, all spent waiting on 
OM.
- Client-side status conversion is 1.2–1.6% of RS CPU (`toFileStatusAdapter`, 
`getBlockLocations`, `OmKeyInfo.getFromProtobuf` for the status).
Parsing the `GetFileStatusResponse` `KeyLocationList` is ~3% of the reopen 
subtree.
- OM-side cost (`refresh` + response encode) is not visible from RS profiles. 
**Measure on OM before and after.**

*Proposed fix*

1. `BasicRootedOzoneFileSystem.getFileStatus(Path)` (and 
`BasicOzoneFileSystem`) call the adapter with `headOp=true`. They return a plain
`FileStatus` (no `BlockLocation[]`). Length, mtime, owner, replication, EC 
policy and encryption flags come from the same `KeyInfo` fields as
today.
2. `getFileBlockLocations(FileStatus, start, len)`: when the status is not a 
`LocatedFileStatus` and is a file, fetch a full status (`headOp=false`)
and compute the range from it, instead of `super.getFileBlockLocations` (which 
returns a fake `localhost` location).
3. Override `getFileBlockLocations(Path, start, len)` to fetch the full status 
directly, so a path-based call stays at **1** RPC.
4. `listStatus` / `listLocatedStatus` / `listFiles` are unchanged; they keep 
their own location handling.
5. Optional escape hatch: `ozone.fs.getfilestatus.include.block.locations` 
(default `false`) restores today's `LocatedFileStatus` from
`getFileStatus`.

{code:java}
// BasicRootedOzoneFileSystem
public FileStatus getFileStatus(Path f) throws IOException {
return TracingUtil.executeInNewSpan("ofs getFileStatus",
() -> convertFileStatus(getFileStatusAdapter(f, !includeBlockLocations)));
}
{code}

*Old OM compatibility*

An OM without HDDS-15678's response stripping still returns locations on a head 
op, but they are unrefreshed (no pipeline). The client must
ignore `KeyLocationList` whenever it sent `headOp=true`, whatever the OM 
version. With that rule no version gate is needed. Old OMs still
skip `refresh` on head ops (that check predates HDDS-15678).

*Compatibility / side effects*

- **Behavior change:** `getFileStatus` no longer returns a `LocatedFileStatus`.
- A caller that casts the result to `LocatedFileStatus` breaks; in-tree, check 
`ozonefs` tests and the `BasicOzoneFileSystem` copy.
- A caller that does `getFileStatus` then `getFileBlockLocations(status)` now 
pays 2 OM RPCs instead of 1. MapReduce/Spark/Hive split
planning uses `listLocatedStatus`, so it is unaffected; one-off single-file 
planners pay +1 RPC.
- No proto change. No new OM version.

*Tests*

- Unit (adapter, Mockito): `getFileStatus` sends `headOp=true`. The result has 
the correct length/mtime/owner/EC fields and is not a
`LocatedFileStatus`. `getFileBlockLocations(status)` sends exactly one 
`GetFileStatus` with `headOp=false` and returns real locations.
`getFileBlockLocations(path)` sends exactly one RPC.
- Integration: `TestRootedOzoneFileSystem` / `TestOzoneFileSystem` locality 
tests still return real datanode hosts. EC and Ratis keys,
encrypted keys.
- Benchmark: `getFileStatus` latency/throughput A/B on a multi-block EC key 
(n=3 per arm, sequential), with OM CPU per call.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to