mirror of
https://github.com/pgsty/minio.git
synced 2026-11-09 17:21:51 +03:00
98fd7004e810cd996dc220276e494c03189ced16
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b10fd0e9c0 |
fix(ilm): report refused purges of all versions, and account their keys
An expiry of all versions of a key purges exactly that key, and the purge can refuse it or stop early. Those outcomes were hard to see, and the scanner reported a key it had queued as if it were already gone. - Refusals and failures of a purge are counted in expiry_incomplete_total with their own reasons: tier_unsupported (a version is in a remote tier), budget (stopped after progress; the next expiry continues), changed (the latest version a batch matched changed) and history_unavailable. They are traced with the reason and send no removal event. A partial purge keeps its audit record, now with the reason. A tier refusal is also logged, once per key and hour, in words. - A drive that cannot be read or decoded during the purge's own drive check now returns errDeleteAllHistoryUnavailable, which names the cause and stays a write quorum error (503) for API callers. - The scanner does not queue an expiry of all versions whose latest version is hot when the pool holds a version in a remote tier: the purge would refuse it each cycle. It counts each such observation as tier_unsupported_skipped, once per drive scanner and cycle. A tiered version only another pool holds is unknown here, so the purge still decides; a transitioned latest version keeps the transitioned expiry. The tier predicate is shared with the purge's own check, for FileInfo and ObjectInfo, and excludes free versions. - The scanner accounts every version of a key under an expiry of all versions at its size, queued or not, instead of as already removed. Usage, and so hard quota, drops after a fresh scan of the subtree once the purge succeeded. The alerts on many or large versions count the versions of a key that is not queued. - A lifecycle expiry never deletes a prefix: DeleteObject refuses DeletePrefix with Expiration.Expire as InvalidArgument. No caller sends it since expiries of all versions became purges; a force delete of a prefix is unchanged. Not done from the plan: queuing an MRF heal per version when a drive's xl.meta fails to decode. Object heal does not rewrite metadata that fails its CRC check (it reports the drive as unknown and skips it), so those heals would not repair the drive. Such a key stays refused until its metadata on that drive is repaired. Tests: TestPurgeAllVersionsRefusalReasons, TestPurgeAllVersionsRefusesCorruptDrive, TestScannerSkipsDeleteAllForTieredKey and TestPoolsDeleteObjectRejectsExpirePrefix are new. Tests that expected the scanner to queue a refused purge, the predictive accounting, or the old prefix options are converted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Feng Ruohang <rh@vonng.com> |
||
|
|
303e340292 |
fix(batch): authorize batch jobs as their submitter
A batch job ran with the server's object access, whoever submitted it, and acted on versions that Object Lock protects. Submitter: StartBatchJob binds the authenticated credential to the job (type, access key, parent, identity revision and a keyed fingerprint). Submission, every start and every object resolve the binding against IAM and evaluate the action with the submitter's policies and session policy. A credential that is gone, disabled, expired or changed fails the job. A policy statement that would need request context the job does not have refuses the action. With an authorization plugin, the plugin and the session policy must both allow. A refusal is persisted as the job's failure reason and ends the job. A job stored without a binding fails and has to be submitted again; a definition holds one job type. Expire deletes each older version on its own, checking retention and legal hold and authorizing it under the delete's lock; a locked version is left and counted. Until the exact-key purge is integrated, a retainVersions: 0 key is refused when a version the walk saw is locked. Pull writes refuse to replace a locked destination version, use the destination's versioning, validate copied retention and apply default retention. Rotation leaves locked versions as they are. The status reports versionsSkippedLocked, keysRefused and the failure reason. Expire and rotation persist their cursor together with these counts, so a resumed job counts each version once. Describe returns a redacted copy of the job. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Feng Ruohang <rh@vonng.com> |
||
|
|
2b228f678c |
fix(ilm): purge only the expired key's own versions in delete-all
An expiry of all versions (ExpiredObjectAllVersions, DelMarkerExpiration, and batch expiration with the default purge) asked the pools layer for a prefix delete. The pools layer rebuilt the options, so the request ran as a recursive delete of the key's directory in every erasure set of every pool. Object a/b is stored inside the directory of a, so every key under a/ was removed with it, however new, with one audit entry and one notification for a alone. The rebuilt options also skipped the lifecycle recheck, so on a single pool a version written after the decision was deleted too, and tiered versions lost their metadata without free versions. The expiry worker, the migration expiry and batch expiration now ask for a purge with the in-memory ObjectOptions.DeleteAllVersions: - DeleteObject hands it to the purge under the object lock, before the all-pools check. ILM decides with the unchanged lifecycleEventsAllPools, on a single pool too; batch needs the version its walk matched to still be the latest. A second read of each pool's authoritative history records every copy, older writes of the same ID included, and must equal the approval. Anything else deletes nothing. - Before deleting, the purge reads every drive of each set that holds a copy. It refuses the key when a drive cannot be read, when any revision of an approved version there is transitioned, or, with Object Lock, when retention or a legal hold protects one. It then deletes on exactly the drive handles it checked. - Versions are deleted by ID with the drives' version delete, which only removes the object directory once it is empty: oldest first, for each version older writes before the copy reads choose, and the latest last, only once every older version is gone from every pool. No marker, replication state or free version is written. The purge stops at the first error, repeats a quorum-successful delete on the drives that missed it while the lock is held, and stops before the latest version at a budget of 1000 versions or one minute, reads included. - The ILM audit entry records how many versions were removed. A purge that failed after it began to delete is audited as partial and sends no removal event. Batch counts come from the purge; a key whose latest version changed is not expired, and a failed delete marker fails the job. The option is rejected with conflicting options and by every layer below the pools. Force delete and internal prefix deletes keep DeletePrefix. Delete-all of a transitioned latest version keeps its current path, and a key with tiered older versions is refused. On a single pool the purge relies on the lock-domain fix for writer exclusion. Reviewed adversarially in two design rounds and four patch rounds; the last approved with nits, which are applied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Feng Ruohang <rh@vonng.com> |