Files
pgsql-jellyfin/docs/POSTGRESQL_TROUBLESHOOTING.md
wjones a3eb4b1b57 Add automatic PostgreSQL database creation and migration
- Added Jellyfin.Database.Providers.Postgres project with full EF Core migration support for PostgreSQL.
- Implemented automatic database creation and privilege assignment on startup.
- Generated initial migration and model snapshot for PostgreSQL schema.
- Updated build, test, and dependency files to include PostgreSQL provider and Npgsql packages.
- Added PowerShell script for generating and testing PostgreSQL migrations.
- No changes to application logic outside database provider/migration infrastructure.
2026-02-22 18:51:24 -05:00

303 lines
7.6 KiB
Markdown

# PostgreSQL Troubleshooting Guide
This guide helps resolve common issues when using PostgreSQL with Jellyfin.
## SynchronizationLockException Error
### Error Message
```
System.Threading.SynchronizationLockException: The write lock is being released without being held.
```
### Cause
This error occurs when using `Pessimistic` locking behavior with PostgreSQL. The issue stems from:
- EF Core interceptors executing on different threads during async operations
- `ReaderWriterLockSlim.IsWriteLockHeld` being thread-local, not async-context-aware
- Transaction and command interceptors both trying to acquire locks
### Solution 1: Use NoLock Behavior (Recommended)
PostgreSQL has built-in MVCC (Multi-Version Concurrency Control) and transaction isolation, making application-level pessimistic locking unnecessary and potentially problematic.
**Update your `config/database.xml`:**
```xml
<LockingBehavior>NoLock</LockingBehavior>
```
**Complete PostgreSQL Configuration:**
```xml
<?xml version="1.0" encoding="utf-8"?>
<DatabaseConfigurationOptions>
<DatabaseType>Jellyfin-PostgreSQL</DatabaseType>
<LockingBehavior>NoLock</LockingBehavior>
<CustomProviderOptions>
<Options>
<CustomDatabaseOption>
<Key>host</Key>
<Value>localhost</Value>
</CustomDatabaseOption>
<CustomDatabaseOption>
<Key>database</Key>
<Value>jellyfin</Value>
</CustomDatabaseOption>
<CustomDatabaseOption>
<Key>username</Key>
<Value>jellyfin</Value>
</CustomDatabaseOption>
<CustomDatabaseOption>
<Key>password</Key>
<Value>your_password</Value>
</CustomDatabaseOption>
</Options>
</CustomProviderOptions>
</DatabaseConfigurationOptions>
```
### Solution 2: Fixed Pessimistic Locking (If Needed)
The pessimistic locking implementation has been updated to use `AsyncLocal<int>` for tracking lock depth across async operations. However, this is **not recommended** for PostgreSQL as it adds unnecessary overhead.
If you must use pessimistic locking:
1. Ensure you have the latest code with the `AsyncLocal` fix
2. Use with caution as it may impact performance
3. Monitor for deadlocks in application logs
## Connection Issues
### Error: "Could not connect to server"
**Checks:**
1. Verify PostgreSQL is running:
```bash
# Linux/macOS
systemctl status postgresql
# Windows (PowerShell)
Get-Service -Name postgresql*
```
2. Test connection manually:
```bash
psql -h localhost -U jellyfin -d jellyfin
```
3. Check `pg_hba.conf` authentication settings:
```
# Allow local connections
host jellyfin jellyfin 127.0.0.1/32 md5
host jellyfin jellyfin ::1/128 md5
```
4. Restart PostgreSQL after changing configuration:
```bash
# Linux/macOS
sudo systemctl restart postgresql
# Windows
Restart-Service postgresql*
```
### Error: "Password authentication failed"
1. Reset the password:
```sql
ALTER USER jellyfin WITH PASSWORD 'new_secure_password';
```
2. Update `database.xml` with the new password
3. Ensure password doesn't contain XML special characters (`<`, `>`, `&`, `'`, `"`). If it does, use XML encoding:
- `<` → `&lt;`
- `>` → `&gt;`
- `&` → `&amp;`
- `'` → `&apos;`
- `"` → `&quot;`
## Migration Issues
### Error: "Database migration failed"
1. Check PostgreSQL version:
```bash
psql --version
```
Minimum required: PostgreSQL 12
2. Verify database exists and is accessible:
```bash
psql -h localhost -U jellyfin -d jellyfin -c "SELECT version();"
```
3. Check database user permissions:
```sql
-- Connect as postgres superuser
GRANT ALL PRIVILEGES ON DATABASE jellyfin TO jellyfin;
GRANT ALL PRIVILEGES ON SCHEMA public TO jellyfin;
```
4. Enable detailed logging:
```xml
<CustomDatabaseOption>
<Key>EnableSensitiveDataLogging</Key>
<Value>True</Value>
</CustomDatabaseOption>
```
## Performance Issues
### Slow Queries
1. **Enable Connection Pooling** (should be default):
```xml
<CustomDatabaseOption>
<Key>pooling</Key>
<Value>True</Value>
</CustomDatabaseOption>
```
2. **Increase Command Timeout** for large libraries:
```xml
<CustomDatabaseOption>
<Key>command-timeout</Key>
<Value>60</Value>
</CustomDatabaseOption>
```
3. **Optimize PostgreSQL** configuration in `postgresql.conf`:
```
shared_buffers = 256MB # 25% of RAM for dedicated server
effective_cache_size = 1GB # 50-75% of RAM
maintenance_work_mem = 64MB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1 # For SSD storage
effective_io_concurrency = 200 # For SSD storage
work_mem = 4MB
```
4. **Create Indexes** for common queries (EF Core migrations should handle this, but verify):
```sql
-- Check existing indexes
SELECT * FROM pg_indexes WHERE schemaname = 'public';
```
### High Memory Usage
PostgreSQL connection pooling maintains connections. To reduce:
```xml
<CustomDatabaseOption>
<Key>pooling</Key>
<Value>False</Value>
</CustomDatabaseOption>
```
⚠️ **Warning**: Disabling pooling will impact performance.
## Debugging
### Enable Detailed SQL Logging
Add to `config/database.xml`:
```xml
<CustomDatabaseOption>
<Key>EnableSensitiveDataLogging</Key>
<Value>True</Value>
</CustomDatabaseOption>
```
⚠️ **Security Warning**: This logs SQL queries including parameter values. Only use for debugging and disable in production.
### Check Jellyfin Logs
Logs are located at:
- Linux: `/var/log/jellyfin/`
- Windows: `%PROGRAMDATA%\Jellyfin\Server\log\`
- Docker: `/config/log/`
Look for lines containing:
- `PostgreSQL connection:`
- `The database locking mode has been set to:`
- Database errors in the startup sequence
### Monitor PostgreSQL Logs
Enable query logging in `postgresql.conf`:
```
log_statement = 'all' # Log all queries (very verbose)
log_min_duration_statement = 1000 # Log queries taking > 1 second
```
Then check PostgreSQL logs:
- Linux: `/var/log/postgresql/`
- Windows: `%PROGRAMDATA%\PostgreSQL\<version>\data\log\`
## Common Configuration Mistakes
### 1. Wrong Locking Behavior
**Don't use:**
```xml
<LockingBehavior>Pessimistic</LockingBehavior>
```
**Use instead:**
```xml
<LockingBehavior>NoLock</LockingBehavior>
```
### 2. Missing CustomProviderOptions
PostgreSQL requires `CustomProviderOptions` even though it's now a built-in provider (for backward compatibility).
### 3. Incorrect Port Format
**Wrong:**
```xml
<Value>postgresql://localhost:5432</Value>
```
**Correct:**
```xml
<CustomDatabaseOption>
<Key>host</Key>
<Value>localhost</Value>
</CustomDatabaseOption>
<CustomDatabaseOption>
<Key>port</Key>
<Value>5432</Value>
</CustomDatabaseOption>
```
## Recovery Steps
If Jellyfin won't start due to database issues:
1. **Stop Jellyfin**
2. **Backup Current Configuration**
```bash
cp config/database.xml config/database.xml.backup
```
3. **Switch Back to SQLite** (temporary):
```xml
<?xml version="1.0" encoding="utf-8"?>
<DatabaseConfigurationOptions>
<DatabaseType>Jellyfin-SQLite</DatabaseType>
<LockingBehavior>NoLock</LockingBehavior>
</DatabaseConfigurationOptions>
```
4. **Restart Jellyfin** and verify it works
5. **Fix PostgreSQL configuration** and try again
## Getting Help
If you're still experiencing issues:
1. Enable detailed logging (see Debugging section above)
2. Collect logs from both Jellyfin and PostgreSQL
3. Note your configuration (without password)
4. Check Jellyfin forums/GitHub issues with:
- Error messages
- PostgreSQL version
- Jellyfin version
- Operating system