Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions perf/cleanup_perf_docs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#!/usr/bin/env bash
set -euo pipefail

# Cleanup perf-created docs by API.
# Modes:
# - single: delete docs created by single-user benchmark (SDEL-*)
# - multi : delete docs created by multi-user benchmark (PDEL-*)
# - all : both (default)

BASE_URL="${BASE_URL:-http://localhost:8080}"
SESSION_COOKIE_NAME="${SESSION_COOKIE_NAME:-JSESSIONID}"
INSECURE_TLS="${INSECURE_TLS:-0}"

MODE="${MODE:-all}" # single | multi | all
USER_PASSWORD="${USER_PASSWORD:-Testtest1}"
TEST_EMAIL="${TEST_EMAIL:-test@test.com}"

USER_PREFIX="${USER_PREFIX:-perfdel}"
USER_DOMAIN="${USER_DOMAIN:-test.com}"
USER_COUNT="${USER_COUNT:-100}"
SEARCH_PAGE_SIZE="${SEARCH_PAGE_SIZE:-100}"

if [[ "${MODE}" != "single" && "${MODE}" != "multi" && "${MODE}" != "all" ]]; then
echo "MODE must be one of: single | multi | all" >&2
exit 1
fi

if ! [[ "${USER_COUNT}" =~ ^[0-9]+$ ]] || [[ "${USER_COUNT}" -lt 0 ]]; then
echo "USER_COUNT must be a non-negative integer" >&2
exit 1
fi

if [[ "${INSECURE_TLS}" == "1" ]]; then
CURL_BASE=(curl -k -sS)
else
CURL_BASE=(curl -sS)
fi

pad3() {
printf "%03d" "$1"
}

login_cookie() {
local email="$1"
local headers body status cookie
headers="$(mktemp)"
body="$(mktemp)"

status="$(
"${CURL_BASE[@]}" -o "${body}" -D "${headers}" -w '%{http_code}' \
-H 'Content-Type: application/json' \
-X POST "${BASE_URL}/api/user/login" \
-d "{\"email\":\"${email}\",\"password\":\"${USER_PASSWORD}\"}"
)"

if [[ "${status}" != "200" ]]; then
rm -f "${headers}" "${body}"
return 1
fi

cookie="$(
grep -i '^set-cookie:' "${headers}" \
| tr -d '\r' \
| sed -n "s/^set-cookie:[[:space:]]*${SESSION_COOKIE_NAME}=\\([^;]*\\).*/\\1/p" \
| head -n 1
)"
rm -f "${headers}" "${body}"

[[ -n "${cookie}" ]] || return 1
printf '%s' "${cookie}"
}

search_doc_ids() {
local cookie="$1"
local keyword="$2"
local body

body="$(
"${CURL_BASE[@]}" \
-H "Cookie: ${SESSION_COOKIE_NAME}=${cookie}" \
-H 'Content-Type: application/json' \
"${BASE_URL}/api/document/search?keyword=${keyword}&page=0&size=${SEARCH_PAGE_SIZE}&sort=updatedAt&order=desc"
)"

printf '%s' "${body}" | node -e '
const fs = require("fs");
const raw = fs.readFileSync(0, "utf8");
let json;
try {
json = JSON.parse(raw);
} catch {
process.exit(0);
}
const content = Array.isArray(json.content) ? json.content : [];
for (const row of content) {
if (row && row.id != null) console.log(row.id);
}
'
}

delete_doc() {
local cookie="$1"
local doc_id="$2"
local status

status="$(
"${CURL_BASE[@]}" -o /dev/null -w '%{http_code}' \
-H "Cookie: ${SESSION_COOKIE_NAME}=${cookie}" \
-H 'Content-Type: application/json' \
-X DELETE "${BASE_URL}/api/document/${doc_id}"
)"
[[ "${status}" == "204" ]]
}

build_users() {
if [[ "${MODE}" == "single" || "${MODE}" == "all" ]]; then
printf '%s\n' "${TEST_EMAIL}"
fi

if [[ "${MODE}" == "multi" || "${MODE}" == "all" ]]; then
local i=1
while [[ "${i}" -le "${USER_COUNT}" ]]; do
printf "%s_u%s@%s\n" "${USER_PREFIX}" "$(pad3 "${i}")" "${USER_DOMAIN}"
i=$((i + 1))
done
fi
}

build_keywords() {
if [[ "${MODE}" == "single" || "${MODE}" == "all" ]]; then
printf '%s\n' "SDEL-"
fi

if [[ "${MODE}" == "multi" || "${MODE}" == "all" ]]; then
printf '%s\n' "PDEL-"
fi
}

echo "[cleanup] BASE_URL=${BASE_URL} MODE=${MODE} INSECURE_TLS=${INSECURE_TLS}"

total_deleted=0
total_failed=0
users_processed=0

while IFS= read -r email; do
[[ -z "${email}" ]] && continue

cookie="$(login_cookie "${email}" || true)"
if [[ -z "${cookie}" ]]; then
echo "[cleanup][skip] login failed: ${email}"
continue
fi

users_processed=$((users_processed + 1))

while IFS= read -r keyword; do
[[ -z "${keyword}" ]] && continue
while true; do
ids="$(search_doc_ids "${cookie}" "${keyword}" || true)"
if [[ -z "${ids}" ]]; then
break
fi

deleted_this_round=0
while IFS= read -r id; do
[[ -z "${id}" ]] && continue
if delete_doc "${cookie}" "${id}"; then
total_deleted=$((total_deleted + 1))
deleted_this_round=$((deleted_this_round + 1))
else
total_failed=$((total_failed + 1))
echo "[cleanup][warn] delete failed: user=${email}, docId=${id}"
fi
done <<< "${ids}"

# Avoid infinite loop if all deletes fail in this page.
if [[ "${deleted_this_round}" -eq 0 ]]; then
break
fi
done
done < <(build_keywords)
done < <(build_users | awk '!seen[$0]++')

echo "[cleanup] users processed=${users_processed}, docs deleted=${total_deleted}, failed=${total_failed}"
echo "[cleanup] Mongo cleanup is async via outbox worker."
25 changes: 25 additions & 0 deletions perf/delete/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
- 생성된 문서를 찾아 삭제만 수행
- `perf/delete/compare_delete_summary.mjs`
- 두 브랜치 결과 비교 표 출력
- `perf/cleanup_perf_docs.sh`
- 생성된 perf 문서 정리 (`MODE=multi` 또는 `MODE=all`)

## 0) App run (example)

Expand Down Expand Up @@ -110,3 +112,26 @@ node perf/delete/compare_delete_summary.mjs \
- 동일 DB 스펙, 동일 JVM 옵션
- 워밍업 1회 후 본측정 3회 이상 (평균/편차 사용)
- 브랜치 순서 바꿔서 반복 (`dev -> refactor`, `refactor -> dev`)

## 6) Cleanup

다중 유저 테스트 데이터(`PDEL-*`) 정리:

```bash
BASE_URL=http://localhost:8080 \
MODE=multi \
USER_PREFIX=perfdel USER_DOMAIN=test.com USER_COUNT=100 \
USER_PASSWORD=Testtest1 \
bash perf/cleanup_perf_docs.sh
```

staging HTTPS(자체 서명 인증서)면:

```bash
BASE_URL=https://<stg-domain-or-ip>:8443 \
INSECURE_TLS=1 \
MODE=multi \
USER_PREFIX=perfdel USER_DOMAIN=test.com USER_COUNT=100 \
USER_PASSWORD=Testtest1 \
bash perf/cleanup_perf_docs.sh
```
4 changes: 3 additions & 1 deletion perf/delete/seed_dataset.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ function buildCommitBody(title, branchId) {
data: {
id: blockId,
type: 'paragraph',
text: `${title}-text-${i}`,
data: {
text: `${title}-text-${i}`,
},
},
});
blockOrders.push(blockId);
Expand Down
23 changes: 23 additions & 0 deletions perf/single_delete/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
- 두 결과 JSON 비교 표 출력
- `results/`
- 실행 결과 JSON 저장
- `../cleanup_perf_docs.sh`
- 생성된 perf 문서 정리 (`MODE=single` 또는 `MODE=all`)

## Environment variables

Expand Down Expand Up @@ -91,3 +93,24 @@ node perf/single_delete/compare_single_delete_summary.mjs \
- 이 벤치는 `setup()`에서 데이터를 생성하고, 본 실행에서 삭제만 측정합니다.
- `commit` 삭제는 서비스 제약(leaf이며 root/from commit이 아니어야 함)을 만족하도록 데이터셋을 생성합니다.
- 진짜 single-user 조건 유지를 위해 실행 VU를 강제로 1로 고정했습니다.

## Cleanup

단일 유저 테스트 데이터(`SDEL-*`) 정리:

```bash
BASE_URL='http://localhost:8080' \
MODE=single \
TEST_EMAIL='test@test.com' USER_PASSWORD='Testtest1' \
bash perf/cleanup_perf_docs.sh
```

staging HTTPS(자체 서명 인증서)면:

```bash
BASE_URL='https://<stg-domain-or-ip>:8443' \
INSECURE_TLS=1 \
MODE=single \
TEST_EMAIL='test@test.com' USER_PASSWORD='Testtest1' \
bash perf/cleanup_perf_docs.sh
```
4 changes: 3 additions & 1 deletion perf/single_delete/single_user_delete_benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ function buildCommitBody(title, branchId) {
data: {
id: blockId,
type: 'paragraph',
text: `${title}-text-${i}`,
data: {
text: `${title}-text-${i}`,
},
},
});
blockOrders.push(blockId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
import io.ejangs.docsa.global.exception.CustomException;
import io.ejangs.docsa.global.exception.errorcode.BranchErrorCode;
import io.ejangs.docsa.global.exception.errorcode.DocErrorCode;
import io.ejangs.docsa.global.mongo.deletion.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.DomainType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.OriginType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.TriggerType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutboxFactory;
import io.ejangs.docsa.global.mongo.deletion.util.MongoDeleteMapper;
import io.ejangs.docsa.global.mongo.outbox.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.DomainType;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.OriginType;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.TriggerType;
import io.ejangs.docsa.global.mongo.outbox.app.MongoDeleteOutboxFactory;
import io.ejangs.docsa.global.mongo.outbox.util.MongoDeleteMapper;
import io.ejangs.docsa.global.util.RenewUpdatedAtHelper;

import java.util.*;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package io.ejangs.docsa.domain.branch.app.create;

import io.ejangs.docsa.domain.branch.dto.response.BranchCreateResponse;
import io.ejangs.docsa.global.mongo.deletion.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.DomainType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.OriginType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.TriggerType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutboxFactory;
import io.ejangs.docsa.global.mongo.outbox.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.DomainType;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.OriginType;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.TriggerType;
import io.ejangs.docsa.global.mongo.outbox.app.MongoDeleteOutboxFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
import io.ejangs.docsa.domain.doc.entity.Doc;
import io.ejangs.docsa.global.exception.CustomException;
import io.ejangs.docsa.global.exception.errorcode.CommitErrorCode;
import io.ejangs.docsa.global.mongo.deletion.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.DomainType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.OriginType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.TriggerType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutboxFactory;
import io.ejangs.docsa.global.mongo.deletion.util.MongoIdsCollector;
import io.ejangs.docsa.global.mongo.outbox.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.DomainType;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.OriginType;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.TriggerType;
import io.ejangs.docsa.global.mongo.outbox.app.MongoDeleteOutboxFactory;
import io.ejangs.docsa.global.mongo.outbox.util.MongoIdsCollector;
import io.ejangs.docsa.global.util.RenewUpdatedAtHelper;
import java.util.List;
import java.util.Map;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
import io.ejangs.docsa.domain.commit.dto.request.CreateCommitRequest;
import io.ejangs.docsa.domain.commit.entity.Commit;
import io.ejangs.docsa.domain.doc.entity.Doc;
import io.ejangs.docsa.global.mongo.deletion.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.DomainType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.OriginType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.TriggerType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutboxFactory;
import io.ejangs.docsa.global.mongo.outbox.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.DomainType;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.OriginType;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.TriggerType;
import io.ejangs.docsa.global.mongo.outbox.app.MongoDeleteOutboxFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import io.ejangs.docsa.domain.commit.util.CommitBlockSequenceMapper;
import io.ejangs.docsa.global.exception.CustomException;
import io.ejangs.docsa.global.exception.errorcode.BlockSequenceErrorCode;
import io.ejangs.docsa.global.mongo.deletion.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.outbox.dto.MongoIdsDto;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
import io.ejangs.docsa.domain.edge.entity.Edge;
import io.ejangs.docsa.domain.edge.util.EdgeMapper;
import io.ejangs.docsa.domain.save.app.SaveQueryService;
import io.ejangs.docsa.global.mongo.deletion.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.DomainType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.OriginType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutbox.TriggerType;
import io.ejangs.docsa.global.mongo.deletion.entity.MongoDeleteOutboxFactory;
import io.ejangs.docsa.global.mongo.outbox.dto.MongoIdsDto;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.DomainType;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.OriginType;
import io.ejangs.docsa.global.mongo.outbox.entity.MongoDeleteOutbox.TriggerType;
import io.ejangs.docsa.global.mongo.outbox.app.MongoDeleteOutboxFactory;
import io.ejangs.docsa.global.util.RenewUpdatedAtHelper;
import java.util.List;
import java.util.Optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import io.ejangs.docsa.domain.block.dto.response.BlockDto;
import io.ejangs.docsa.domain.commit.app.CommitQueryService;
import io.ejangs.docsa.domain.commit.document.CommitBlockSequence;
import io.ejangs.docsa.global.mongo.deletion.dto.CommitMongoIdsDto;
import io.ejangs.docsa.global.mongo.outbox.dto.CommitMongoIdsDto;
import io.ejangs.docsa.domain.commit.util.CommitBlockSequenceMapper;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand Down
Loading
Loading