Client A :
@@ -38,9 +38,8 @@
-
+
-
+
@@ -77,7 +77,7 @@
});
await client.attach(doc, {
- initialPresence: { username: `username-${shortUniqueID}` },
+ initialPresence: { username: `username-${shortUniqueID()}` },
});
doc.update((root) => {
diff --git a/public/style.css b/public/style.css
index 24c705218..7e634bd10 100644
--- a/public/style.css
+++ b/public/style.css
@@ -1,13 +1,34 @@
-body {
- background: white;
+/* ============== RESET CSS ============= */
+/* prettier-ignore */
+html, body, div, span, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, address, cite, code,
+del, dfn, em, img, strong, sub,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+ box-sizing: border-box;
}
-
-h2 {
- margin-top: 1.6em;
+ol,
+ul {
+ list-style: none;
}
-li {
- list-style: none;
+/* ============= COMMON CSS ============= */
+body {
+ margin: 8px;
+ background: white;
}
button {
@@ -17,22 +38,61 @@ button {
align-items: center;
}
+#network-status,
+#online-clients,
+#log-holder {
+ margin: 1rem;
+ font-family: monospace;
+}
+#network-status:before {
+ content: 'network: ';
+}
+#online-clients:before {
+ content: 'online-clients: ';
+}
+#log-holder:before {
+ content: 'root: ';
+}
#network-status span {
display: inline-block;
height: 0.8rem;
width: 0.8rem;
border-radius: 0.4rem;
}
-
-.green {
+#network-status .green {
background-color: green;
}
-
-.red {
+#network-status .red {
background-color: red;
}
-.wrap {
+/* ============= quill.html ============= */
+
+.ql-editor {
+ min-height: 300px;
+ overflow-y: auto;
+ resize: vertical;
+}
+
+#document,
+#document-text {
+ margin: 1rem;
+ font-family: monospace;
+}
+
+#document:before {
+ display: block;
+ content: 'document: ';
+}
+
+#document-text:before {
+ display: block;
+ content: 'text: ';
+}
+
+/* ============ counter.html ============ */
+
+.counter-wrap {
display: flex;
align-items: center;
margin: 1em 0;
@@ -55,46 +115,10 @@ button {
height: 30px;
}
-#network-status:before {
- content: 'network: ';
- font-size: 1rem;
-}
-
-#peers:before {
- display: block;
- content: 'peers: ';
- font-size: 1rem;
-}
-
-#document:before,
-.document:before {
- display: block;
- content: 'document: ';
- font-size: 1rem;
-}
-
-#document-text:before,
-.document-text:before {
- display: block;
- content: 'text: ';
- font-size: 1rem;
-}
-
-#network-status,
-#peers,
-#document,
-.document,
-#document-text,
-.document-text {
- margin: 1rem 0;
- font-family: monospace;
- overflow: scroll;
-}
-
-.ql-editor {
- min-height: 300px;
- overflow-y: auto;
- resize: vertical;
+h2 {
+ margin: 1.6em 0 0.4em;
+ font-weight: bold;
+ font-size: 24px;
}
.increaseButton {
@@ -167,50 +191,3 @@ button {
border: none;
outline: none;
}
-.client-container {
- display: flex;
- width: 95%;
-}
-.client-container .ql-container {
- height: auto;
-}
-#client-a,
-#client-b {
- width: 50%;
- margin: 15px;
-}
-#editor {
- width: 80%;
- margin: 30px 10px;
- padding: 30px 20px;
- border: 1px solid #ccc;
- border-radius: 4px;
-}
-.input-wrapper {
- display: flex;
- flex-direction: column;
- margin: 20px;
- width: 80%;
-}
-.input-wrapper label {
- margin-bottom: 10px;
-}
-.input-wrapper input {
- padding: 10px;
- margin-bottom: 10px;
- border: 1px solid #ccc;
- border-radius: 4px;
- font-size: 14px;
-}
-.input-wrapper button {
- padding: 10px 20px;
- border: none;
- border-radius: 4px;
- background-color: #2196f3;
- color: #fff;
- font-size: 14px;
- cursor: pointer;
-}
-.input-wrapper button:hover {
- background-color: #0d8bf2;
-}
diff --git a/src/document/document.ts b/src/document/document.ts
index a2246dea4..8fce96be5 100644
--- a/src/document/document.ts
+++ b/src/document/document.ts
@@ -66,6 +66,18 @@ import {
PresenceChangeType,
} from '@yorkie-js-sdk/src/document/presence/presence';
+/**
+ * `DocumentOptions` are the options to create a new document.
+ *
+ * @public
+ */
+export interface DocumentOptions {
+ /**
+ * `disableGC` disables garbage collection if true.
+ */
+ disableGC?: boolean;
+}
+
/**
* `DocumentStatus` represents the status of the document.
* @public
@@ -388,6 +400,7 @@ type PathOf
= PathOfInternal<
export class Document {
private key: DocumentKey;
private status: DocumentStatus;
+ private opts: DocumentOptions;
private changeID: ChangeID;
private checkpoint: Checkpoint;
@@ -412,7 +425,9 @@ export class Document {
*/
private presences: Map;
- constructor(key: string) {
+ constructor(key: string, opts?: DocumentOptions) {
+ this.opts = opts || {};
+
this.key = key;
this.status = DocumentStatus.Detached;
this.root = CRDTRoot.create();
@@ -888,6 +903,10 @@ export class Document {
* @internal
*/
public garbageCollect(ticket: TimeTicket): number {
+ if (this.opts.disableGC) {
+ return 0;
+ }
+
if (this.clone) {
this.clone.root.garbageCollect(ticket);
}
diff --git a/test/integration/gc_test.ts b/test/integration/gc_test.ts
index 14ed72e51..7a36fcc2b 100644
--- a/test/integration/gc_test.ts
+++ b/test/integration/gc_test.ts
@@ -50,6 +50,29 @@ describe('Garbage Collection', function () {
assert.equal(0, doc.getGarbageLen());
});
+ it('disable GC test', function () {
+ const doc = new yorkie.Document<{
+ 1: number;
+ 2?: Array;
+ 3: number;
+ }>('test-doc', { disableGC: true });
+
+ doc.update((root) => {
+ root['1'] = 1;
+ root['2'] = [1, 2, 3];
+ root['3'] = 3;
+ }, 'set 1, 2, 3');
+ assert.equal('{"1":1,"2":[1,2,3],"3":3}', doc.toSortedJSON());
+
+ doc.update((root) => {
+ delete root['2'];
+ }, 'deletes 2');
+ assert.equal('{"1":1,"3":3}', doc.toSortedJSON());
+ assert.equal(4, doc.getGarbageLen());
+ assert.equal(0, doc.garbageCollect(MaxTimeTicket));
+ assert.equal(4, doc.getGarbageLen());
+ });
+
it('garbage collection test2', function () {
const size = 10000;
const doc = new yorkie.Document<{ 1?: Array }>('test-doc');