0
# Database Operations
1
2
Data persistence layer with garbage collection, transaction management, and user identification for maintaining collaborative state.
3
4
## Capabilities
5
6
### Database Interface
7
8
The database handles all persistence, cleanup, and state management operations.
9
10
```javascript { .api }
11
/**
12
* Yjs Database interface for persistence and state management
13
*/
14
interface YjsDatabase {
15
/**
16
* Stop the garbage collector
17
* Use when you need to ensure data persistence during critical operations
18
*/
19
stopGarbageCollector(): void;
20
21
/**
22
* Garbage collection status
23
* True if garbage collection is active
24
*/
25
gc: boolean;
26
27
/**
28
* Garbage collection timeout in milliseconds
29
* Default: 50000ms (50 seconds)
30
*/
31
gcTimeout: number;
32
33
/**
34
* User ID for this client instance
35
* Used for conflict resolution and user tracking
36
*/
37
userId: string;
38
}
39
```
40
41
**Usage Examples:**
42
43
```javascript
44
// Basic database configuration
45
Y({
46
db: { name: 'indexeddb' },
47
connector: { name: 'websockets-client', room: 'db-demo', url: 'ws://localhost:1234' },
48
share: { doc: 'Text' }
49
}).then(function (y) {
50
const db = y.db;
51
52
console.log('User ID:', db.userId);
53
console.log('Garbage collection active:', db.gc);
54
console.log('GC timeout:', db.gcTimeout, 'ms');
55
});
56
57
// Long-running critical operations
58
Y({
59
db: { name: 'leveldb' },
60
connector: { name: 'test', room: 'critical-ops' },
61
share: { data: 'Map' }
62
}).then(function (y) {
63
const db = y.db;
64
65
function performCriticalOperation() {
66
// Stop garbage collection during critical operations
67
console.log('Starting critical operation - stopping GC');
68
db.stopGarbageCollector();
69
70
// Perform operations that must not be interrupted
71
performDataMigration();
72
73
console.log('Critical operation complete');
74
// GC remains stopped - restart manually if needed
75
}
76
77
document.getElementById('migrate').onclick = performCriticalOperation;
78
});
79
```
80
81
### Garbage Collection Management
82
83
Control automatic cleanup of unused collaborative data.
84
85
```javascript { .api }
86
/**
87
* Stop the garbage collector
88
* Use when you need to ensure data persistence during critical operations
89
*/
90
stopGarbageCollector(): void;
91
```
92
93
**Usage Examples:**
94
95
```javascript
96
// Data archiving with GC control
97
Y({
98
db: { name: 'indexeddb' },
99
connector: { name: 'websockets-client', room: 'archive', url: 'ws://localhost:1234' },
100
share: {
101
documents: 'Map',
102
archive: 'Array'
103
}
104
}).then(function (y) {
105
const db = y.db;
106
107
function archiveOldDocuments() {
108
// Prevent GC from cleaning up data we're about to archive
109
db.stopGarbageCollector();
110
console.log('GC stopped for archiving process');
111
112
// Process all documents
113
const docs = y.share.documents;
114
const archive = y.share.archive;
115
116
// Move old documents to archive
117
Object.keys(docs).forEach(function(docId) {
118
const doc = docs.get(docId);
119
if (isOldDocument(doc)) {
120
archive.push([{
121
id: docId,
122
content: doc,
123
archivedAt: Date.now(),
124
archivedBy: db.userId
125
}]);
126
docs.delete(docId);
127
}
128
});
129
130
console.log('Archiving complete. GC remains stopped.');
131
}
132
133
// Scheduled archiving
134
setInterval(archiveOldDocuments, 24 * 60 * 60 * 1000); // Daily
135
});
136
137
// Development mode - preserve all changes
138
Y({
139
db: { name: 'memory' },
140
connector: { name: 'test', room: 'development' },
141
share: { workspace: 'Map' }
142
}).then(function (y) {
143
const db = y.db;
144
145
if (window.location.hostname === 'localhost') {
146
// In development, keep all data for debugging
147
db.stopGarbageCollector();
148
console.log('Development mode: GC disabled');
149
150
// Add debug info to workspace
151
y.share.workspace.set('debug', {
152
gcDisabled: true,
153
userId: db.userId,
154
startTime: Date.now()
155
});
156
}
157
});
158
```
159
160
### Database Configuration Properties
161
162
Monitor and configure database behavior at runtime.
163
164
```javascript { .api }
165
/**
166
* Garbage collection status
167
* True if garbage collection is active, false if stopped
168
*/
169
gc: boolean;
170
171
/**
172
* Garbage collection timeout in milliseconds
173
* Default: 50000ms (50 seconds)
174
* Controls how long unused operations are kept before cleanup
175
*/
176
gcTimeout: number;
177
```
178
179
**Usage Examples:**
180
181
```javascript
182
// Monitoring database health
183
Y({
184
db: { name: 'indexeddb' },
185
connector: { name: 'websockets-client', room: 'monitoring', url: 'ws://localhost:1234' },
186
share: { status: 'Map' }
187
}).then(function (y) {
188
const db = y.db;
189
190
// Regular health checks
191
function checkDatabaseHealth() {
192
const health = {
193
userId: db.userId,
194
gcActive: db.gc,
195
gcTimeout: db.gcTimeout,
196
timestamp: Date.now()
197
};
198
199
y.share.status.set('dbHealth_' + db.userId, health);
200
console.log('Database health:', health);
201
}
202
203
setInterval(checkDatabaseHealth, 30000); // Every 30 seconds
204
205
// Alert on GC issues
206
if (!db.gc && db.gcTimeout > 60000) {
207
console.warn('GC disabled with long timeout - memory usage may grow');
208
}
209
});
210
211
// Performance tuning
212
Y({
213
db: { name: 'leveldb' },
214
connector: { name: 'webrtc', room: 'performance' },
215
share: { data: 'Array' }
216
}).then(function (y) {
217
const db = y.db;
218
219
// Adjust GC timeout based on usage patterns
220
if (isHighVolumeEnvironment()) {
221
// Shorter timeout for high-volume scenarios
222
console.log('High-volume mode: original GC timeout', db.gcTimeout);
223
// Note: gcTimeout is read-only, shown here for monitoring
224
}
225
226
// Log GC status changes
227
let previousGcStatus = db.gc;
228
setInterval(function() {
229
if (db.gc !== previousGcStatus) {
230
console.log('GC status changed:', previousGcStatus, '->', db.gc);
231
previousGcStatus = db.gc;
232
}
233
}, 1000);
234
});
235
```
236
237
### User Identity Management
238
239
Track user identity for conflict resolution and audit trails.
240
241
```javascript { .api }
242
/**
243
* User ID for this client instance
244
* Used for conflict resolution and user tracking
245
* Automatically generated or set via connector configuration
246
*/
247
userId: string;
248
```
249
250
**Usage Examples:**
251
252
```javascript
253
// User activity tracking
254
Y({
255
db: { name: 'indexeddb' },
256
connector: {
257
name: 'websockets-client',
258
room: 'activity-tracking',
259
url: 'ws://localhost:1234',
260
generateUserId: false // Use server-provided ID
261
},
262
share: {
263
document: 'Text',
264
activity: 'Array'
265
}
266
}).then(function (y) {
267
const db = y.db;
268
const userId = db.userId;
269
270
console.log('Current user ID:', userId);
271
272
// Track user actions
273
y.share.document.observe(function(event) {
274
y.share.activity.push([{
275
userId: userId,
276
action: event.type,
277
timestamp: Date.now(),
278
details: {
279
index: event.index,
280
length: event.length
281
}
282
}]);
283
});
284
});
285
286
// Multi-user conflict resolution
287
Y({
288
db: { name: 'memory' },
289
connector: {
290
name: 'webrtc',
291
room: 'conflict-resolution',
292
generateUserId: true // Generate local ID
293
},
294
share: {
295
counter: 'Map',
296
log: 'Array'
297
}
298
}).then(function (y) {
299
const db = y.db;
300
const userId = db.userId;
301
302
function updateCounter(operation, value) {
303
const entry = {
304
userId: userId,
305
operation: operation,
306
value: value,
307
timestamp: Date.now()
308
};
309
310
// Log all operations with user attribution
311
y.share.log.push([entry]);
312
313
// Apply operation
314
const current = y.share.counter.get('value') || 0;
315
if (operation === 'increment') {
316
y.share.counter.set('value', current + value);
317
} else if (operation === 'decrement') {
318
y.share.counter.set('value', current - value);
319
}
320
321
console.log('Operation by', userId, ':', operation, value);
322
}
323
324
// User-attributed operations
325
document.getElementById('increment').onclick = function() {
326
updateCounter('increment', 1);
327
};
328
329
document.getElementById('decrement').onclick = function() {
330
updateCounter('decrement', 1);
331
};
332
});
333
334
// Audit trail with user identification
335
Y({
336
db: { name: 'indexeddb' },
337
connector: {
338
name: 'websockets-client',
339
room: 'audit-trail',
340
url: 'ws://localhost:1234'
341
},
342
share: {
343
document: 'Text',
344
auditLog: 'Array'
345
}
346
}).then(function (y) {
347
const db = y.db;
348
349
// Create audit entry for all changes
350
function createAuditEntry(eventType, details) {
351
return {
352
userId: db.userId,
353
eventType: eventType,
354
timestamp: Date.now(),
355
details: details
356
};
357
}
358
359
// Document change auditing
360
y.share.document.observe(function(event) {
361
const auditEntry = createAuditEntry('document_change', {
362
changeType: event.type,
363
position: event.index,
364
length: event.length,
365
values: event.values
366
});
367
368
y.share.auditLog.push([auditEntry]);
369
});
370
371
// Connection auditing
372
y.connector.onUserEvent(function(event) {
373
const auditEntry = createAuditEntry('user_event', {
374
action: event.action,
375
affectedUser: event.user,
376
currentUser: db.userId
377
});
378
379
y.share.auditLog.push([auditEntry]);
380
});
381
});
382
```
383
384
## Database Adapters
385
386
### Memory Database
387
- **Name**: `memory`
388
- **Persistence**: None (data lost on page refresh)
389
- **Use Case**: Development, testing, temporary sessions
390
- **Performance**: Fastest (in-memory operations)
391
392
### IndexedDB Database
393
- **Name**: `indexeddb`
394
- **Persistence**: Browser local storage
395
- **Use Case**: Client-side applications, offline support
396
- **Performance**: Good (asynchronous browser storage)
397
398
### LevelDB Database
399
- **Name**: `leveldb`
400
- **Persistence**: File system (Node.js)
401
- **Use Case**: Server applications, long-term storage
402
- **Performance**: Excellent (optimized key-value store)
403
404
## Garbage Collection
405
406
### Purpose
407
Garbage collection automatically removes unused operations and conflicts from the database to prevent unbounded memory growth in long-running collaborative sessions.
408
409
### Behavior
410
- **Default**: Enabled with 50-second timeout
411
- **Scope**: Removes operations no longer needed for conflict resolution
412
- **Safety**: Preserves all data required for current state and synchronization
413
414
### Control Scenarios
415
- **Stop during critical operations** to prevent data loss
416
- **Development mode** to preserve all changes for debugging
417
- **Archival processes** to ensure complete data migration
418
- **Performance testing** to measure worst-case memory usage