fix: handle fs duplicates on write (#2910)

This commit is contained in:
Daniel Salazar
2026-05-05 00:33:55 -07:00
committed by GitHub
parent 838d6a7178
commit ad3f0f6c2e
2 changed files with 57 additions and 11 deletions
+21 -4
View File
@@ -1,12 +1,25 @@
name: Docker Image CI
# Builds only on calver tag pushes: YY.MM or YY.MM.p (all numeric).
# Each build publishes three tags: <version>, latest, main.
# Two ways in:
# - push of a calver tag (YY.MM or YY.MM.p) → publishes <version>, latest, main
# - workflow_dispatch → publishes latest + main from whichever ref the user
# picks in the Actions UI. Used to fast-forward :latest/:main when the
# branch has moved ahead of the most recent release tag.
on:
push:
tags:
- '[0-9][0-9].[0-9][0-9]'
- '[0-9][0-9].[0-9][0-9].[0-9]*'
workflow_dispatch:
inputs:
push_latest:
description: 'Push :latest tag'
type: boolean
default: true
push_main:
description: 'Push :main tag'
type: boolean
default: true
env:
REGISTRY: ghcr.io
@@ -22,6 +35,7 @@ jobs:
steps:
- name: Validate calver tag
if: github.event_name == 'push'
env:
REF_NAME: ${{ github.ref_name }}
run: |
@@ -51,10 +65,13 @@ jobs:
uses: docker/metadata-action@v5
with:
images: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
# type=ref,event=tag only emits on tag pushes, so manual runs skip
# the calver tag and just publish whichever of latest / main the
# dispatch inputs asked for. On a tag push, both default to true.
tags: |
type=ref,event=tag
type=raw,value=latest
type=raw,value=main
type=raw,value=latest,enable=${{ github.event_name == 'push' || inputs.push_latest }}
type=raw,value=main,enable=${{ github.event_name == 'push' || inputs.push_main }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
+36 -7
View File
@@ -2722,17 +2722,46 @@ export class FSService extends PuterService {
}
}
const created = await this.stores.fsEntry.createNonFileEntry({
userId,
parent,
name,
kind: 'directory',
thumbnail: input.thumbnail ?? null,
});
let created: FSEntry;
try {
created = await this.stores.fsEntry.createNonFileEntry({
userId,
parent,
name,
kind: 'directory',
thumbnail: input.thumbnail ?? null,
});
} catch (err) {
// Concurrent mkdir race: another caller inserted the same
// (parent_id, name) between our existence check above and the
// INSERT, tripping the unique key. mkdir on an existing dir is
// documented as idempotent — re-fetch and return the winner if
// it's a directory; otherwise surface the same 409 the pre-INSERT
// check would have produced.
if (!this.#isUniqueViolation(err)) throw err;
const insertedPath =
parent.path === '/' ? `/${name}` : `${parent.path}/${name}`;
const raced =
await this.stores.fsEntry.getEntryByPath(insertedPath);
if (raced?.isDir) return raced;
if (raced) {
throw new HttpError(
409,
`An entry already exists at ${insertedPath}`,
);
}
throw err;
}
this.#emitFsEvent('fs.create.directory', created);
return created;
}
#isUniqueViolation(err: unknown): boolean {
if (!(err instanceof Error) || !('code' in err)) return false;
const code = (err as { code?: unknown }).code;
return code === 'ER_DUP_ENTRY' || code === 'SQLITE_CONSTRAINT';
}
/**
* Touch: create an empty file at `path` if missing; otherwise bump
* timestamps.