@@ -59,17 +59,30 @@ def _configure_connection(self, conn):
5959
6060 # Aggressive Synology-optimized settings for network file system performance
6161 conn .execute ('PRAGMA synchronous = OFF' ) # Most aggressive - no FSYNC waits for maximum performance
62- conn .execute ('PRAGMA cache_size = -65536 ' ) # 64MB cache (doubled from 40MB) for better performance
62+ conn .execute ('PRAGMA cache_size = -131072 ' ) # 128MB cache (massive increase for Synology NAS)
6363 conn .execute ('PRAGMA temp_store = MEMORY' ) # Store temp tables in memory
64- conn .execute ('PRAGMA busy_timeout = 60000 ' ) # 60 seconds for Synology I/O (increased from 30s)
65- conn .execute ('PRAGMA mmap_size = 268435456 ' ) # 256MB memory map for better performance
66- conn .execute ('PRAGMA page_size = 32768 ' ) # Larger page size for network shares (32KB )
64+ conn .execute ('PRAGMA busy_timeout = 120000 ' ) # 2 minutes for extreme Synology I/O delays
65+ conn .execute ('PRAGMA mmap_size = 536870912 ' ) # 512MB memory map for network shares
66+ conn .execute ('PRAGMA page_size = 65536 ' ) # Maximum page size for network shares (64KB )
6767
68- # Additional Synology-specific optimizations
68+ # Critical Synology-specific optimizations based on media server research
6969 conn .execute ('PRAGMA locking_mode = EXCLUSIVE' ) # Exclusive locking for single-user scenarios
7070 conn .execute ('PRAGMA count_changes = OFF' ) # Disable change counting for performance
7171 conn .execute ('PRAGMA legacy_file_format = OFF' ) # Use modern file format
7272 conn .execute ('PRAGMA reverse_unordered_selects = OFF' ) # Consistent query results
73+ conn .execute ('PRAGMA compile_options' ) # Check available compile options
74+
75+ # Additional optimizations from Plex/Sonarr research for Synology
76+ conn .execute ('PRAGMA threads = 4' ) # Use multiple threads for operations
77+ conn .execute ('PRAGMA max_page_count = 1073741823' ) # Maximum database size
78+ conn .execute ('PRAGMA default_cache_size = -131072' ) # Set default cache size
79+ conn .execute ('PRAGMA cache_spill = OFF' ) # Prevent cache spilling to disk
80+ conn .execute ('PRAGMA query_only = OFF' ) # Allow write operations
81+ conn .execute ('PRAGMA trusted_schema = ON' ) # Trust schema for performance
82+
83+ # File descriptor and connection optimizations
84+ conn .execute ('PRAGMA analysis_limit = 1000' ) # Limit analysis for performance
85+ conn .execute ('PRAGMA optimize = 0x10002' ) # Advanced optimization flags
7386
7487 else :
7588 if is_synology and not synology_opt_enabled :
@@ -110,19 +123,26 @@ def _configure_connection(self, conn):
110123 result = conn .execute ('PRAGMA journal_mode' ).fetchone ()
111124 if result and result [0 ] == 'wal' :
112125 if is_synology and synology_opt_enabled :
113- # Very aggressive checkpointing for Synology network shares
114- conn .execute ('PRAGMA wal_autocheckpoint = 2000' ) # Much less frequent checkpoints
115- conn .execute ('PRAGMA journal_size_limit = 268435456' ) # 256MB journal size limit
126+ # Extremely aggressive checkpointing for Synology network shares
127+ conn .execute ('PRAGMA wal_autocheckpoint = 5000' ) # Very infrequent checkpoints for performance
128+ conn .execute ('PRAGMA journal_size_limit = 1073741824' ) # 1GB journal size limit (maximum)
129+
130+ # Additional WAL optimizations for Synology
131+ try :
132+ conn .execute ('PRAGMA wal_checkpoint = PASSIVE' ) # Non-blocking checkpoint mode
133+ except Exception :
134+ pass # Not all SQLite versions support this
116135 else :
117136 # Conservative checkpointing for other systems
118137 conn .execute ('PRAGMA wal_autocheckpoint = 500' ) # More frequent checkpoints for Docker
119138 conn .execute ('PRAGMA journal_size_limit = 67108864' ) # 64MB journal size limit
120139
121- # Force checkpoint and truncate to clean up WAL file
122- try :
123- conn .execute ('PRAGMA wal_checkpoint(TRUNCATE)' )
124- except Exception as checkpoint_error :
125- logger .debug (f"WAL checkpoint failed (non-critical): { checkpoint_error } " )
140+ # Force checkpoint and truncate to clean up WAL file (skip for Synology aggressive mode)
141+ if not (is_synology and synology_opt_enabled ):
142+ try :
143+ conn .execute ('PRAGMA wal_checkpoint(TRUNCATE)' )
144+ except Exception as checkpoint_error :
145+ logger .debug (f"WAL checkpoint failed (non-critical): { checkpoint_error } " )
126146
127147 # Test the configuration worked (skip integrity check for aggressive Synology mode)
128148 if not (is_synology and synology_opt_enabled ):
@@ -138,8 +158,17 @@ def _configure_connection(self, conn):
138158 cache_size = conn .execute ('PRAGMA cache_size' ).fetchone ()[0 ]
139159 mmap_size = conn .execute ('PRAGMA mmap_size' ).fetchone ()[0 ]
140160 page_size = conn .execute ('PRAGMA page_size' ).fetchone ()[0 ]
141- logger .info (f"Synology optimizations applied: journal={ journal_mode } , sync={ sync_mode } , "
142- f"cache={ abs (cache_size / 1024 ):.1f} MB, mmap={ mmap_size / 1024 / 1024 :.0f} MB, page={ page_size } B" )
161+ busy_timeout = conn .execute ('PRAGMA busy_timeout' ).fetchone ()[0 ]
162+
163+ if synology_opt_enabled :
164+ logger .info (f"AGGRESSIVE Synology optimizations applied: journal={ journal_mode } , sync={ sync_mode } , "
165+ f"cache={ abs (cache_size / 1024 ):.1f} MB, mmap={ mmap_size / 1024 / 1024 :.0f} MB, "
166+ f"page={ page_size } B, timeout={ busy_timeout / 1000 :.0f} s" )
167+ logger .info ("Applied Synology-specific optimizations: threads=4, cache_spill=OFF, "
168+ "exclusive_locking=ON, analysis_limit=1000" )
169+ else :
170+ logger .info (f"Standard Synology optimizations applied: journal={ journal_mode } , sync={ sync_mode } , "
171+ f"cache={ abs (cache_size / 1024 ):.1f} MB, mmap={ mmap_size / 1024 / 1024 :.0f} MB, page={ page_size } B" )
143172
144173 except Exception as e :
145174 logger .error (f"Error configuring database connection: { e } " )
@@ -149,17 +178,50 @@ def _configure_connection(self, conn):
149178 def get_connection (self ):
150179 """Get a configured SQLite connection with Synology NAS compatibility"""
151180 try :
152- conn = sqlite3 .connect (self .db_path )
181+ # Use timeout and additional connection parameters for Synology compatibility
182+ is_synology = self ._detect_synology_nas ()
183+ synology_opt_enabled = os .environ .get ('HUNTARR_SYNOLOGY_OPTIMIZATIONS' , 'true' ).lower () == 'true'
184+
185+ if is_synology and synology_opt_enabled :
186+ # Aggressive connection settings for Synology
187+ conn = sqlite3 .connect (
188+ self .db_path ,
189+ timeout = 120.0 , # 2 minutes timeout for network file systems
190+ isolation_level = None , # Autocommit mode for better performance
191+ check_same_thread = False # Allow multi-threaded access
192+ )
193+ else :
194+ # Standard connection settings
195+ conn = sqlite3 .connect (
196+ self .db_path ,
197+ timeout = 30.0 ,
198+ check_same_thread = False
199+ )
200+
153201 self ._configure_connection (conn )
202+
154203 # Test the connection by running a simple query
155204 conn .execute ("SELECT name FROM sqlite_master WHERE type='table' LIMIT 1" ).fetchone ()
156205 return conn
206+
157207 except (sqlite3 .DatabaseError , sqlite3 .OperationalError ) as e :
158208 if "file is not a database" in str (e ) or "database disk image is malformed" in str (e ):
159209 logger .error (f"Database corruption detected: { e } " )
160210 self ._handle_database_corruption ()
161211 # Try connecting again after recovery
162- conn = sqlite3 .connect (self .db_path )
212+ if is_synology and synology_opt_enabled :
213+ conn = sqlite3 .connect (
214+ self .db_path ,
215+ timeout = 120.0 ,
216+ isolation_level = None ,
217+ check_same_thread = False
218+ )
219+ else :
220+ conn = sqlite3 .connect (
221+ self .db_path ,
222+ timeout = 30.0 ,
223+ check_same_thread = False
224+ )
163225 self ._configure_connection (conn )
164226 return conn
165227 else :
0 commit comments