pgserve 1.0.7 โ 1.0.9-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitguardian.yaml +29 -0
- package/.gitguardianignore +16 -0
- package/.github/release.yml +30 -0
- package/.github/workflows/build-all-platforms.yml +165 -0
- package/.github/workflows/ci.yml +84 -0
- package/.github/workflows/release.yml +208 -0
- package/Makefile +129 -62
- package/README.md +57 -18
- package/bin/pglite-server.js +17 -4
- package/bun.lock +409 -0
- package/bunfig.toml +28 -0
- package/eslint.config.js +5 -0
- package/knip.json +1 -2
- package/package.json +13 -14
- package/scripts/release.cjs +190 -0
- package/scripts/{test-npx.sh โ test-bunx.sh} +19 -10
- package/src/cluster.js +202 -104
- package/src/logger.js +71 -23
- package/src/pg-wire.js +869 -0
- package/src/postgres.js +295 -124
- package/src/protocol.js +3 -2
- package/src/restore.js +57 -70
- package/src/router.js +218 -107
- package/src/sync.js +70 -77
- package/tests/benchmarks/runner.js +117 -51
- package/tests/multi-tenant.test.js +39 -30
- package/.claude/settings.local.json +0 -11
package/Makefile
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# ==========================================
|
|
2
|
-
# ๐ฆ
|
|
2
|
+
# ๐ฆ pgserve - Embedded PostgreSQL Server
|
|
3
3
|
# ==========================================
|
|
4
4
|
|
|
5
5
|
.DEFAULT_GOAL := help
|
|
@@ -24,14 +24,26 @@ VERSION := $(shell grep '"version"' package.json | head -1 | sed 's/.*"version":
|
|
|
24
24
|
.PHONY: help
|
|
25
25
|
help: ## Show this help
|
|
26
26
|
@echo ""
|
|
27
|
-
@echo "$(PURPLE)$(BOLD)๐ฆ
|
|
28
|
-
@echo "$(CYAN)
|
|
27
|
+
@echo "$(PURPLE)$(BOLD)๐ฆ pgserve$(RESET) - v$(VERSION)"
|
|
28
|
+
@echo "$(CYAN)Embedded PostgreSQL server with multi-tenant support$(RESET)"
|
|
29
29
|
@echo ""
|
|
30
30
|
@echo "$(BOLD)Quick Commands:$(RESET)"
|
|
31
|
-
@echo " $(PURPLE)
|
|
31
|
+
@echo " $(PURPLE)release-rc$(RESET) Create RC release locally"
|
|
32
|
+
@echo " $(PURPLE)release-stable$(RESET) Promote RC to stable"
|
|
32
33
|
@echo " $(PURPLE)test-local$(RESET) Test server locally"
|
|
33
34
|
@echo " $(PURPLE)pm2-start$(RESET) Start server with PM2"
|
|
34
|
-
@echo "
|
|
35
|
+
@echo ""
|
|
36
|
+
@echo "$(BOLD)CI/CD Workflow:$(RESET)"
|
|
37
|
+
@echo " 1. Create PR with changes"
|
|
38
|
+
@echo " 2. Add 'rc' label โ auto-publishes to npm @next"
|
|
39
|
+
@echo " 3. Add 'stable' label โ promotes to npm @latest"
|
|
40
|
+
@echo ""
|
|
41
|
+
@echo "$(BOLD)Build Executables:$(RESET)"
|
|
42
|
+
@echo " $(PURPLE)build$(RESET) Build for current platform"
|
|
43
|
+
@echo " $(PURPLE)build-all$(RESET) Build for all platforms (Linux, macOS, Windows)"
|
|
44
|
+
@echo " $(PURPLE)build-linux$(RESET) Build for Linux (x64 + arm64)"
|
|
45
|
+
@echo " $(PURPLE)build-macos$(RESET) Build for macOS (x64 + arm64)"
|
|
46
|
+
@echo " $(PURPLE)build-windows$(RESET) Build for Windows (x64)"
|
|
35
47
|
@echo ""
|
|
36
48
|
@echo "$(BOLD)Development:$(RESET)"
|
|
37
49
|
@echo " $(PURPLE)install$(RESET) Install dependencies"
|
|
@@ -48,9 +60,21 @@ help: ## Show this help
|
|
|
48
60
|
.PHONY: install
|
|
49
61
|
install: ## Install dependencies
|
|
50
62
|
@echo "$(CYAN)๐ฆ Installing dependencies...$(RESET)"
|
|
51
|
-
@
|
|
63
|
+
@bun install
|
|
52
64
|
@echo "$(GREEN)โ
Dependencies installed!$(RESET)"
|
|
53
65
|
|
|
66
|
+
.PHONY: test
|
|
67
|
+
test: ## Run tests
|
|
68
|
+
@echo "$(CYAN)๐งช Running tests...$(RESET)"
|
|
69
|
+
@bun test
|
|
70
|
+
@echo "$(GREEN)โ
Tests passed!$(RESET)"
|
|
71
|
+
|
|
72
|
+
.PHONY: bench
|
|
73
|
+
bench: ## Run benchmarks
|
|
74
|
+
@echo "$(CYAN)๐ Running benchmarks...$(RESET)"
|
|
75
|
+
@bun tests/benchmarks/runner.js
|
|
76
|
+
@echo "$(GREEN)โ
Benchmarks complete!$(RESET)"
|
|
77
|
+
|
|
54
78
|
# ==========================================
|
|
55
79
|
# ๐งช Testing
|
|
56
80
|
# ==========================================
|
|
@@ -78,21 +102,21 @@ pm2-start: ## Start server with PM2
|
|
|
78
102
|
|
|
79
103
|
pm2-stop: ## Stop PM2 instance
|
|
80
104
|
@echo "$(CYAN)๐ Stopping PM2 instance...$(RESET)"
|
|
81
|
-
@pm2 stop "
|
|
82
|
-
@pm2 delete "
|
|
105
|
+
@pm2 stop "pgserve" 2>/dev/null || true
|
|
106
|
+
@pm2 delete "pgserve" 2>/dev/null || true
|
|
83
107
|
@pm2 save
|
|
84
108
|
@echo "$(GREEN)โ
PM2 instance stopped!$(RESET)"
|
|
85
109
|
|
|
86
110
|
pm2-restart: ## Restart PM2 instance
|
|
87
111
|
@echo "$(CYAN)๐ Restarting PM2 instance...$(RESET)"
|
|
88
|
-
@pm2 restart "
|
|
112
|
+
@pm2 restart "pgserve" 2>/dev/null || $(MAKE) pm2-start
|
|
89
113
|
@echo "$(GREEN)โ
PM2 instance restarted!$(RESET)"
|
|
90
114
|
|
|
91
115
|
pm2-logs: ## Show PM2 logs
|
|
92
|
-
@pm2 logs "
|
|
116
|
+
@pm2 logs "pgserve" --lines 50
|
|
93
117
|
|
|
94
118
|
pm2-status: ## Show PM2 status
|
|
95
|
-
@pm2 status "
|
|
119
|
+
@pm2 status "pgserve"
|
|
96
120
|
|
|
97
121
|
# ==========================================
|
|
98
122
|
# ๐ Pre-publish Checks
|
|
@@ -139,7 +163,86 @@ check-files: ## Check required files exist
|
|
|
139
163
|
@echo "$(GREEN)โ
All required files present$(RESET)"
|
|
140
164
|
|
|
141
165
|
# ==========================================
|
|
142
|
-
#
|
|
166
|
+
# ๐จ Build Standalone Executables
|
|
167
|
+
# ==========================================
|
|
168
|
+
DIST_DIR := dist
|
|
169
|
+
|
|
170
|
+
.PHONY: build build-linux build-macos build-windows build-all clean-dist
|
|
171
|
+
|
|
172
|
+
$(DIST_DIR):
|
|
173
|
+
@mkdir -p $(DIST_DIR)
|
|
174
|
+
|
|
175
|
+
build: $(DIST_DIR) ## Build standalone executable for current platform
|
|
176
|
+
@echo "$(CYAN)๐จ Building standalone executable...$(RESET)"
|
|
177
|
+
@bun build --compile bin/pglite-server.js --outfile $(DIST_DIR)/pgserve
|
|
178
|
+
@echo "$(GREEN)โ
Built: $(DIST_DIR)/pgserve$(RESET)"
|
|
179
|
+
|
|
180
|
+
build-linux: $(DIST_DIR) ## Build for Linux (x64 + arm64)
|
|
181
|
+
@echo "$(CYAN)๐ง Building for Linux...$(RESET)"
|
|
182
|
+
@bun build --compile --target=bun-linux-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-linux-x64
|
|
183
|
+
@bun build --compile --target=bun-linux-arm64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-linux-arm64
|
|
184
|
+
@echo "$(GREEN)โ
Built: $(DIST_DIR)/pgserve-linux-x64$(RESET)"
|
|
185
|
+
@echo "$(GREEN)โ
Built: $(DIST_DIR)/pgserve-linux-arm64$(RESET)"
|
|
186
|
+
|
|
187
|
+
build-macos: $(DIST_DIR) ## Build for macOS (x64 + arm64)
|
|
188
|
+
@echo "$(CYAN)๐ Building for macOS...$(RESET)"
|
|
189
|
+
@bun build --compile --target=bun-darwin-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-darwin-x64
|
|
190
|
+
@bun build --compile --target=bun-darwin-arm64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-darwin-arm64
|
|
191
|
+
@echo "$(GREEN)โ
Built: $(DIST_DIR)/pgserve-darwin-x64$(RESET)"
|
|
192
|
+
@echo "$(GREEN)โ
Built: $(DIST_DIR)/pgserve-darwin-arm64$(RESET)"
|
|
193
|
+
|
|
194
|
+
build-windows: $(DIST_DIR) ## Build for Windows (x64)
|
|
195
|
+
@echo "$(CYAN)๐ช Building for Windows...$(RESET)"
|
|
196
|
+
@bun build --compile --target=bun-windows-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-windows-x64.exe
|
|
197
|
+
@echo "$(GREEN)โ
Built: $(DIST_DIR)/pgserve-windows-x64.exe$(RESET)"
|
|
198
|
+
|
|
199
|
+
build-all: build-linux build-macos build-windows ## Build for all platforms
|
|
200
|
+
@echo ""
|
|
201
|
+
@echo "$(GREEN)$(BOLD)โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ$(RESET)"
|
|
202
|
+
@echo "$(GREEN)$(BOLD)โ ๐ All platform builds complete! โ$(RESET)"
|
|
203
|
+
@echo "$(GREEN)$(BOLD)โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ$(RESET)"
|
|
204
|
+
@echo ""
|
|
205
|
+
@ls -lh $(DIST_DIR)/
|
|
206
|
+
@echo ""
|
|
207
|
+
|
|
208
|
+
clean-dist: ## Clean build artifacts
|
|
209
|
+
@echo "$(CYAN)๐งน Cleaning dist...$(RESET)"
|
|
210
|
+
@rm -rf $(DIST_DIR)
|
|
211
|
+
@echo "$(GREEN)โ
Dist cleaned!$(RESET)"
|
|
212
|
+
|
|
213
|
+
# ==========================================
|
|
214
|
+
# ๐ CI/CD Release (Automated)
|
|
215
|
+
# ==========================================
|
|
216
|
+
# Releases are triggered by GitHub Actions when PRs are merged with labels:
|
|
217
|
+
# - 'rc' label โ Creates RC release (1.0.8 โ 1.0.9-rc.1)
|
|
218
|
+
# - 'stable' label โ Promotes RC to stable (1.0.9-rc.1 โ 1.0.9)
|
|
219
|
+
#
|
|
220
|
+
# See .github/workflows/release.yml for full automation.
|
|
221
|
+
# ==========================================
|
|
222
|
+
.PHONY: release-rc release-stable release-dry
|
|
223
|
+
|
|
224
|
+
release-rc: ## Create RC release locally (for testing)
|
|
225
|
+
@echo "$(CYAN)๐ข Creating RC release...$(RESET)"
|
|
226
|
+
@node scripts/release.cjs --action bump-rc
|
|
227
|
+
@echo ""
|
|
228
|
+
@echo "$(GREEN)โ
RC release created!$(RESET)"
|
|
229
|
+
@echo "$(YELLOW)Push with: git push && git push --tags$(RESET)"
|
|
230
|
+
|
|
231
|
+
release-stable: ## Promote RC to stable locally (for testing)
|
|
232
|
+
@echo "$(CYAN)๐ Promoting to stable...$(RESET)"
|
|
233
|
+
@node scripts/release.cjs --action promote
|
|
234
|
+
@echo ""
|
|
235
|
+
@echo "$(GREEN)โ
Stable release created!$(RESET)"
|
|
236
|
+
@echo "$(YELLOW)Push with: git push && git push --tags$(RESET)"
|
|
237
|
+
|
|
238
|
+
release-dry: ## Dry-run release (no changes)
|
|
239
|
+
@echo "$(CYAN)๐ Dry-run release...$(RESET)"
|
|
240
|
+
@node scripts/release.cjs --action bump-rc --dry-run
|
|
241
|
+
@echo ""
|
|
242
|
+
@echo "$(GREEN)โ
Dry-run complete (no changes made)$(RESET)"
|
|
243
|
+
|
|
244
|
+
# ==========================================
|
|
245
|
+
# ๐ฆ Manual Publish (Deprecated)
|
|
143
246
|
# ==========================================
|
|
144
247
|
.PHONY: pre-publish publish publish-dry
|
|
145
248
|
pre-publish: check-git check-npm check-version check-files ## Run all pre-publish checks
|
|
@@ -151,57 +254,21 @@ publish-dry: pre-publish ## Dry-run publish (test without actually publishing)
|
|
|
151
254
|
@echo "$(GREEN)โ
Dry-run successful!$(RESET)"
|
|
152
255
|
@echo "$(YELLOW)To actually publish, run: make publish$(RESET)"
|
|
153
256
|
|
|
154
|
-
publish:
|
|
257
|
+
publish: ## โ ๏ธ [DEPRECATED] Use PR labels instead
|
|
155
258
|
@echo ""
|
|
156
|
-
@echo "$(
|
|
157
|
-
@echo "$(
|
|
158
|
-
@echo "$(
|
|
259
|
+
@echo "$(YELLOW)$(BOLD)โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ$(RESET)"
|
|
260
|
+
@echo "$(YELLOW)$(BOLD)โ โ ๏ธ Manual publish is DEPRECATED โ$(RESET)"
|
|
261
|
+
@echo "$(YELLOW)$(BOLD)โ โ$(RESET)"
|
|
262
|
+
@echo "$(YELLOW)$(BOLD)โ Use PR labels for automated releases: โ$(RESET)"
|
|
263
|
+
@echo "$(YELLOW)$(BOLD)โ โข Add 'rc' label โ RC release (npm @next) โ$(RESET)"
|
|
264
|
+
@echo "$(YELLOW)$(BOLD)โ โข Add 'stable' label โ Promote to stable (npm @latest) โ$(RESET)"
|
|
265
|
+
@echo "$(YELLOW)$(BOLD)โ โ$(RESET)"
|
|
266
|
+
@echo "$(YELLOW)$(BOLD)โ Local testing: โ$(RESET)"
|
|
267
|
+
@echo "$(YELLOW)$(BOLD)โ make release-rc Create RC locally โ$(RESET)"
|
|
268
|
+
@echo "$(YELLOW)$(BOLD)โ make release-stable Promote locally โ$(RESET)"
|
|
269
|
+
@echo "$(YELLOW)$(BOLD)โ make release-dry Dry-run (no changes) โ$(RESET)"
|
|
270
|
+
@echo "$(YELLOW)$(BOLD)โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ$(RESET)"
|
|
159
271
|
@echo ""
|
|
160
|
-
@echo "$(CYAN)Current version: v$(VERSION)$(RESET)"
|
|
161
|
-
@echo ""
|
|
162
|
-
@echo "$(CYAN)๐ Bumping patch version...$(RESET)"
|
|
163
|
-
@NEW_VER=$$(node -e "const p=require('./package.json'); const v=p.version.split('.'); v[2]=parseInt(v[2])+1; console.log(v.join('.'))"); \
|
|
164
|
-
git tag -d "v$$NEW_VER" 2>/dev/null || true; \
|
|
165
|
-
git push origin --delete "v$$NEW_VER" 2>/dev/null || true
|
|
166
|
-
@npm version patch -m "chore: bump version to %s"
|
|
167
|
-
@NEW_VERSION=$$(grep '"version"' package.json | head -1 | sed 's/.*"version": "\(.*\)".*/\1/'); \
|
|
168
|
-
echo "$(GREEN)โ
Version bumped to $$NEW_VERSION$(RESET)"; \
|
|
169
|
-
echo ""; \
|
|
170
|
-
echo "$(CYAN)๐ค Pushing to GitHub...$(RESET)"; \
|
|
171
|
-
git push && git push --tags; \
|
|
172
|
-
echo "$(GREEN)โ
Pushed to GitHub!$(RESET)"; \
|
|
173
|
-
echo ""; \
|
|
174
|
-
echo "$(CYAN)Package: $(PACKAGE_NAME)@$$NEW_VERSION$(RESET)"; \
|
|
175
|
-
echo ""; \
|
|
176
|
-
read -p "$(YELLOW)Confirm publish? [y/N] $(RESET)" -n 1 -r; \
|
|
177
|
-
echo; \
|
|
178
|
-
if [[ ! $$REPLY =~ ^[Yy]$$ ]]; then \
|
|
179
|
-
echo "$(YELLOW)โ ๏ธ Publish cancelled$(RESET)"; \
|
|
180
|
-
exit 1; \
|
|
181
|
-
fi; \
|
|
182
|
-
echo ""; \
|
|
183
|
-
echo "$(CYAN)๐ฆ Publishing to npm...$(RESET)"; \
|
|
184
|
-
npm publish --access public || { echo "$(RED)โ npm publish failed! Run manually: npm publish --access public$(RESET)"; exit 1; }; \
|
|
185
|
-
echo "$(GREEN)โ
Published to npm!$(RESET)"; \
|
|
186
|
-
echo ""; \
|
|
187
|
-
if command -v gh >/dev/null 2>&1; then \
|
|
188
|
-
echo "$(CYAN)๐ Creating GitHub release...$(RESET)"; \
|
|
189
|
-
gh release create "v$$NEW_VERSION" \
|
|
190
|
-
--title "v$$NEW_VERSION" \
|
|
191
|
-
--notes "Multi-instance PostgreSQL embedded server - See README.md for details" \
|
|
192
|
-
|| echo "$(YELLOW)โ ๏ธ GitHub release creation failed (may already exist)$(RESET)"; \
|
|
193
|
-
echo ""; \
|
|
194
|
-
fi; \
|
|
195
|
-
echo "$(GREEN)$(BOLD)โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ$(RESET)"; \
|
|
196
|
-
echo "$(GREEN)$(BOLD)โ ๐พ SUCCESS! Package published! โ$(RESET)"; \
|
|
197
|
-
echo "$(GREEN)$(BOLD)โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ$(RESET)"; \
|
|
198
|
-
echo ""; \
|
|
199
|
-
echo "$(CYAN)๐ฆ Install with:$(RESET)"; \
|
|
200
|
-
echo " npm install -g $(PACKAGE_NAME)"; \
|
|
201
|
-
echo ""; \
|
|
202
|
-
echo "$(CYAN)๐ View on npm:$(RESET)"; \
|
|
203
|
-
echo " https://www.npmjs.com/package/$(PACKAGE_NAME)"; \
|
|
204
|
-
echo ""
|
|
205
272
|
|
|
206
273
|
# ==========================================
|
|
207
274
|
# ๐งน Maintenance
|
|
@@ -215,7 +282,7 @@ clean: ## Clean generated files
|
|
|
215
282
|
|
|
216
283
|
clean-all: clean ## Deep clean (including node_modules)
|
|
217
284
|
@echo "$(CYAN)๐งน Deep cleaning...$(RESET)"
|
|
218
|
-
@rm -rf node_modules package-lock.json pnpm-lock.yaml
|
|
285
|
+
@rm -rf node_modules package-lock.json pnpm-lock.yaml bun.lock
|
|
219
286
|
@echo "$(GREEN)โ
Deep clean complete!$(RESET)"
|
|
220
287
|
|
|
221
288
|
# ==========================================
|
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<p>
|
|
6
6
|
<a href="https://www.npmjs.com/package/pgserve"><img src="https://img.shields.io/npm/v/pgserve?style=flat-square&color=00D9FF" alt="npm version"></a>
|
|
7
7
|
<img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen?style=flat-square" alt="Node.js">
|
|
8
|
+
<img src="https://img.shields.io/badge/bun-%3E%3D1.0.0-f472b6?style=flat-square" alt="Bun">
|
|
8
9
|
<img src="https://img.shields.io/badge/PostgreSQL-17.7-blue?style=flat-square" alt="PostgreSQL">
|
|
9
10
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="License"></a>
|
|
10
11
|
<a href="https://discord.gg/xcW8c7fF3R"><img src="https://img.shields.io/discord/1095114867012292758?style=flat-square&color=00D9FF&label=discord" alt="Discord"></a>
|
|
@@ -56,6 +57,10 @@ psql postgresql://localhost:5432/myapp
|
|
|
56
57
|
<td><b>Memory Mode</b></td>
|
|
57
58
|
<td>Fast and ephemeral for development (default)</td>
|
|
58
59
|
</tr>
|
|
60
|
+
<tr>
|
|
61
|
+
<td><b>RAM Mode</b></td>
|
|
62
|
+
<td>Use <code>--ram</code> for /dev/shm storage (Linux, 2x faster)</td>
|
|
63
|
+
</tr>
|
|
59
64
|
<tr>
|
|
60
65
|
<td><b>Persistent Mode</b></td>
|
|
61
66
|
<td>Use <code>--data ./path</code> for durable storage</td>
|
|
@@ -87,6 +92,10 @@ npm install -g pgserve
|
|
|
87
92
|
|
|
88
93
|
# Project dependency
|
|
89
94
|
npm install pgserve
|
|
95
|
+
|
|
96
|
+
# With Bun
|
|
97
|
+
bunx pgserve
|
|
98
|
+
bun add pgserve
|
|
90
99
|
```
|
|
91
100
|
|
|
92
101
|
> PostgreSQL binaries are automatically downloaded on first run.
|
|
@@ -101,6 +110,7 @@ pgserve [options]
|
|
|
101
110
|
Options:
|
|
102
111
|
--port <number> PostgreSQL port (default: 8432)
|
|
103
112
|
--data <path> Data directory for persistence (default: in-memory)
|
|
113
|
+
--ram Use RAM storage via /dev/shm (Linux only, fastest)
|
|
104
114
|
--host <host> Host to bind to (default: 127.0.0.1)
|
|
105
115
|
--log <level> Log level: error, warn, info, debug (default: info)
|
|
106
116
|
--cluster Force cluster mode (auto-enabled on multi-core)
|
|
@@ -119,6 +129,9 @@ Options:
|
|
|
119
129
|
# Development (memory mode, auto-clusters on multi-core)
|
|
120
130
|
pgserve
|
|
121
131
|
|
|
132
|
+
# RAM mode (Linux only, 2x faster)
|
|
133
|
+
pgserve --ram
|
|
134
|
+
|
|
122
135
|
# Persistent storage
|
|
123
136
|
pgserve --data /var/lib/pgserve
|
|
124
137
|
|
|
@@ -237,40 +250,46 @@ pgserve --sync-to "postgresql://..." --sync-databases "myapp,tenant_*"
|
|
|
237
250
|
|
|
238
251
|
## Performance
|
|
239
252
|
|
|
253
|
+
### Benchmark Results
|
|
254
|
+
|
|
240
255
|
<table>
|
|
241
256
|
<tr>
|
|
242
257
|
<th>Scenario</th>
|
|
243
258
|
<th>SQLite</th>
|
|
244
259
|
<th>PGlite</th>
|
|
245
|
-
<th>
|
|
246
|
-
<th>pgserve</th>
|
|
260
|
+
<th>pgserve (Node)</th>
|
|
261
|
+
<th>pgserve (Bun)</th>
|
|
262
|
+
<th>pgserve --ram</th>
|
|
247
263
|
</tr>
|
|
248
264
|
<tr>
|
|
249
265
|
<td><b>Concurrent Writes</b> (10 agents)</td>
|
|
250
|
-
<td>
|
|
251
|
-
<td>
|
|
252
|
-
<td>
|
|
253
|
-
<td
|
|
266
|
+
<td>85 qps</td>
|
|
267
|
+
<td>211 qps</td>
|
|
268
|
+
<td>833 qps</td>
|
|
269
|
+
<td>1,754 qps</td>
|
|
270
|
+
<td><b>4,000 qps</b> ๐</td>
|
|
254
271
|
</tr>
|
|
255
272
|
<tr>
|
|
256
|
-
<td><b>Mixed Workload</b
|
|
257
|
-
<td>
|
|
258
|
-
<td>
|
|
259
|
-
<td>
|
|
260
|
-
<td
|
|
273
|
+
<td><b>Mixed Workload</b></td>
|
|
274
|
+
<td>339 qps</td>
|
|
275
|
+
<td>505 qps</td>
|
|
276
|
+
<td>1,017 qps</td>
|
|
277
|
+
<td>999 qps</td>
|
|
278
|
+
<td><b>1,986 qps</b> ๐</td>
|
|
261
279
|
</tr>
|
|
262
280
|
<tr>
|
|
263
281
|
<td><b>Write Lock</b> (50 writers)</td>
|
|
264
|
-
<td>
|
|
265
|
-
<td>
|
|
266
|
-
<td
|
|
267
|
-
<td>
|
|
282
|
+
<td>86 qps</td>
|
|
283
|
+
<td>168 qps</td>
|
|
284
|
+
<td>488 qps</td>
|
|
285
|
+
<td>1,176 qps</td>
|
|
286
|
+
<td><b>4,348 qps</b> ๐</td>
|
|
268
287
|
</tr>
|
|
269
288
|
</table>
|
|
270
289
|
|
|
271
|
-
>
|
|
290
|
+
> **Bun gives 2x throughput** for concurrent writes vs Node.js. **RAM mode adds another 2-4x** on Linux.
|
|
272
291
|
>
|
|
273
|
-
> Run benchmarks: `
|
|
292
|
+
> Run benchmarks: `bun run bench`
|
|
274
293
|
|
|
275
294
|
<br>
|
|
276
295
|
|
|
@@ -320,11 +339,31 @@ pgserve --sync-to "postgresql://..." --sync-databases "myapp,tenant_*"
|
|
|
320
339
|
|
|
321
340
|
## Requirements
|
|
322
341
|
|
|
323
|
-
- **Node.js
|
|
342
|
+
- **Runtime**: Node.js >= 18.0.0 or Bun >= 1.0.0
|
|
324
343
|
- **Platform**: Linux x64, macOS ARM64/x64, Windows x64
|
|
325
344
|
|
|
326
345
|
<br>
|
|
327
346
|
|
|
347
|
+
## Development
|
|
348
|
+
|
|
349
|
+
This project uses Bun for development:
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
# Install dependencies
|
|
353
|
+
bun install
|
|
354
|
+
|
|
355
|
+
# Run tests
|
|
356
|
+
bun test
|
|
357
|
+
|
|
358
|
+
# Run benchmarks
|
|
359
|
+
bun tests/benchmarks/runner.js
|
|
360
|
+
|
|
361
|
+
# Lint
|
|
362
|
+
bun run lint
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
<br>
|
|
366
|
+
|
|
328
367
|
## Contributing
|
|
329
368
|
|
|
330
369
|
Contributions welcome! Fork the repo, create a feature branch, add tests, and submit a PR.
|
package/bin/pglite-server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* pgserve - Embedded PostgreSQL Server
|
|
@@ -44,6 +44,7 @@ USAGE:
|
|
|
44
44
|
OPTIONS:
|
|
45
45
|
--port <number> PostgreSQL port (default: 8432)
|
|
46
46
|
--data <path> Data directory for persistence (default: in-memory)
|
|
47
|
+
--ram Use RAM storage via /dev/shm (Linux only, faster)
|
|
47
48
|
--host <host> Host to bind to (default: 127.0.0.1)
|
|
48
49
|
--log <level> Log level: error, warn, info, debug (default: info)
|
|
49
50
|
--cluster Force cluster mode (auto-enabled on multi-core systems)
|
|
@@ -55,7 +56,8 @@ OPTIONS:
|
|
|
55
56
|
--help Show this help message
|
|
56
57
|
|
|
57
58
|
MODES:
|
|
58
|
-
In-memory (default):
|
|
59
|
+
In-memory (default): Ephemeral temp directory - data lost on restart
|
|
60
|
+
RAM mode (--ram): True RAM via /dev/shm (Linux only, fastest)
|
|
59
61
|
Persistent: Use --data to persist databases to disk
|
|
60
62
|
|
|
61
63
|
EXAMPLES:
|
|
@@ -98,6 +100,7 @@ function parseArgs() {
|
|
|
98
100
|
port: 8432,
|
|
99
101
|
host: '127.0.0.1',
|
|
100
102
|
dataDir: null, // null = memory mode
|
|
103
|
+
useRam: false, // Use /dev/shm for true RAM storage (Linux only)
|
|
101
104
|
logLevel: 'info',
|
|
102
105
|
autoProvision: true,
|
|
103
106
|
cluster: cpuCount > 1, // Auto-enable on multi-core (use --no-cluster to disable)
|
|
@@ -120,6 +123,10 @@ function parseArgs() {
|
|
|
120
123
|
options.dataDir = args[++i];
|
|
121
124
|
break;
|
|
122
125
|
|
|
126
|
+
case '--ram':
|
|
127
|
+
options.useRam = true;
|
|
128
|
+
break;
|
|
129
|
+
|
|
123
130
|
case '--host':
|
|
124
131
|
case '-h':
|
|
125
132
|
options.host = args[++i];
|
|
@@ -178,6 +185,9 @@ function parseArgs() {
|
|
|
178
185
|
async function main() {
|
|
179
186
|
const options = parseArgs();
|
|
180
187
|
const memoryMode = !options.dataDir;
|
|
188
|
+
const storageType = options.dataDir
|
|
189
|
+
? options.dataDir
|
|
190
|
+
: (options.useRam ? '/dev/shm (RAM)' : '(temp directory)');
|
|
181
191
|
|
|
182
192
|
// Only print header if not a cluster worker (workers get PGSERVE_WORKER env)
|
|
183
193
|
if (!process.env.PGSERVE_WORKER) {
|
|
@@ -196,6 +206,7 @@ pgserve - Embedded PostgreSQL Server
|
|
|
196
206
|
port: options.port,
|
|
197
207
|
host: options.host,
|
|
198
208
|
baseDir: options.dataDir,
|
|
209
|
+
useRam: options.useRam,
|
|
199
210
|
logLevel: options.logLevel,
|
|
200
211
|
autoProvision: options.autoProvision,
|
|
201
212
|
workers: options.workers
|
|
@@ -204,13 +215,14 @@ pgserve - Embedded PostgreSQL Server
|
|
|
204
215
|
// Only primary process shows full startup message
|
|
205
216
|
if (server.workers) {
|
|
206
217
|
const stats = server.getStats();
|
|
218
|
+
|
|
207
219
|
console.log(`
|
|
208
220
|
Cluster started successfully!
|
|
209
221
|
|
|
210
222
|
Endpoint: postgresql://${options.host}:${options.port}/<database>
|
|
211
223
|
Mode: ${memoryMode ? 'In-memory (ephemeral)' : 'Persistent'} (Cluster)
|
|
212
224
|
Workers: ${stats.workers} processes
|
|
213
|
-
Data: ${
|
|
225
|
+
Data: ${storageType}
|
|
214
226
|
Auto-create: ${options.autoProvision ? 'Enabled' : 'Disabled'}
|
|
215
227
|
|
|
216
228
|
Examples:
|
|
@@ -226,6 +238,7 @@ Press Ctrl+C to stop
|
|
|
226
238
|
port: options.port,
|
|
227
239
|
host: options.host,
|
|
228
240
|
baseDir: options.dataDir,
|
|
241
|
+
useRam: options.useRam,
|
|
229
242
|
logLevel: options.logLevel,
|
|
230
243
|
autoProvision: options.autoProvision,
|
|
231
244
|
syncTo: options.syncTo,
|
|
@@ -244,7 +257,7 @@ Server started successfully!
|
|
|
244
257
|
|
|
245
258
|
Endpoint: postgresql://${options.host}:${options.port}/<database>
|
|
246
259
|
Mode: ${memoryMode ? 'In-memory (ephemeral)' : 'Persistent'}
|
|
247
|
-
Data: ${
|
|
260
|
+
Data: ${storageType}
|
|
248
261
|
PostgreSQL: Port ${router.pgPort} (internal)
|
|
249
262
|
Auto-create: ${options.autoProvision ? 'Enabled' : 'Disabled'}
|
|
250
263
|
Sync: ${syncStatus}${options.syncDatabases ? ` (${options.syncDatabases})` : ''}
|