Skip to content

Commit 7d0104e

Browse files
committed
Repl issue reproduced
1 parent 506abee commit 7d0104e

File tree

2 files changed

+13480
-85
lines changed

2 files changed

+13480
-85
lines changed

c_playground/main.c

Lines changed: 186 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
#include <assert.h>
22
#include <stdio.h>
3+
#include <stdlib.h>
34
#include <string.h>
5+
#include <unistd.h>
46

57
#include <cbl/CBLCollection.h>
68
#include <cbl/CBLDatabase.h>
79
#include <cbl/CBLDocument.h>
810
#include <cbl/CBLLog.h>
911
#include <cbl/CBLQuery.h>
12+
#include <cbl/CBLReplicator.h>
1013

1114
const char* DOMAINS[] = { "Database", "Query", "Replicator", "Network" };
1215
const char* LEVEL_PREFIX[] = { "((", "_", "", "WARNING: ", "***ERROR: " };
@@ -22,125 +25,223 @@ void log_callback(CBLLogDomain domain, CBLLogLevel level, FLString message) {
2225
);
2326
}
2427

25-
int main(void) {
26-
CBLConsoleLogSink log_sink = {};
27-
log_sink.level = kCBLLogDebug;
28-
log_sink.domains = kCBLLogDomainMaskAll;
29-
30-
CBLLogSinks_SetConsole(log_sink);
31-
32-
// Open database
28+
void startReplication(CBLDatabase *db, bool writer, bool deleter) {
3329
CBLError error;
34-
CBLDatabaseConfiguration config = {FLSTR("/tmp")};
35-
CBLDatabase* db = CBLDatabase_Open(FLSTR("my_db"), &config, &error);
36-
assert(db);
37-
38-
CBLCollection* default_collection = CBLDatabase_DefaultCollection(db, &error);
39-
assert(default_collection);
40-
41-
// Create a document
42-
CBLDocument* doc = CBLDocument_Create();
30+
CBLEndpoint* endpoint = CBLEndpoint_CreateWithURL(FLSTR("wss://sync-gateway-staging.doctolib.com:443/billeo-db"), &error);
31+
assert(endpoint);
32+
33+
char* token = writer ? "0febaaafc5368d7e2f8663e0ee08b024a47278c1"
34+
: (deleter ? "61b8b461214c7d6c6c7365dbc4e824111bc4167a"
35+
: "49230c1a31db39e1d5e96e5fbdf1bf93099b53b5"
36+
);
37+
char cookie[64];
38+
snprintf(cookie, sizeof cookie, "SyncGatewaySession=%s", token);
39+
40+
FLMutableDict headers = FLMutableDict_New();
41+
FLMutableDict_SetString(headers, FLSTR("Cookie"), FLStr(cookie));
42+
43+
FLMutableArray emptyArray = FLMutableArray_New();
44+
FLArray array = FLMutableArray_GetSource(emptyArray);
45+
46+
CBLReplicatorConfiguration config = {
47+
.database = db,
48+
.endpoint = endpoint,
49+
.replicatorType = kCBLReplicatorTypePushAndPull,
50+
.continuous = true,
51+
.disableAutoPurge = true,
52+
.maxAttempts = 1,
53+
.maxAttemptWaitTime = 0,
54+
.heartbeat = 55,
55+
.authenticator = NULL,
56+
.proxy = NULL,
57+
.headers = headers,
58+
.pinnedServerCertificate = FLStr(NULL),
59+
.trustedRootCertificates = FLStr(NULL),
60+
.channels = array,
61+
.documentIDs = array,
62+
.pushFilter = NULL,
63+
.pullFilter = NULL,
64+
.conflictResolver = NULL,
65+
.context = NULL,
66+
.collections = NULL,
67+
.collectionCount = 0,
68+
.acceptParentDomainCookies = false,
69+
};
70+
71+
CBLReplicator* replicator = CBLReplicator_Create(&config, &error);
72+
assert(replicator);
73+
74+
CBLReplicator_Start(replicator, false);
75+
}
4376

44-
FILE* fp = fopen("doc.json", "r");
77+
void createDocuments(CBLDatabase *db) {
78+
CBLError error;
4579

46-
char json_format[4096];
47-
int len = fread(json_format, 1, 4096, fp);
80+
FILE* fp = fopen("replication_issue.json", "r");
81+
if (!fp) {
82+
printf("Failed to open replication_issue.json\n");
83+
return;
84+
}
85+
86+
fseek(fp, 0, SEEK_END);
87+
long file_size = ftell(fp);
88+
fseek(fp, 0, SEEK_SET);
89+
90+
char* json_format = malloc(file_size + 1);
91+
if (!json_format) {
92+
printf("Failed to allocate memory for JSON\n");
93+
fclose(fp);
94+
return;
95+
}
96+
97+
size_t len = fread(json_format, 1, file_size, fp);
98+
json_format[len] = '\0';
4899

49100
fclose(fp);
50101

51102
FLString json = {};
52-
json.buf = &json_format;
103+
json.buf = json_format;
53104
json.size = len;
54-
bool set_doc_content = CBLDocument_SetJSON(doc, json, &error);
55105

56106
// Save the document
57-
bool saved = CBLDatabase_SaveDocument(db, doc, &error);
58-
assert(saved);
59-
60-
CBLDocument_Release(doc);
61-
62-
// Simple array index
63-
CBLArrayIndexConfiguration array_index_config = {};
64-
array_index_config.expressionLanguage = kCBLN1QLLanguage;
65-
array_index_config.path = FLSTR("likes");
66-
array_index_config.expressions = FLSTR("");
107+
const int idOffset = 100;
108+
for (int i = 0; i < 100; ++i) {
109+
char id[64];
110+
snprintf(id, sizeof id, "replication_issue_%d", idOffset + i);
111+
112+
CBLDocument* doc = CBLDocument_CreateWithID(FLStr(id));
113+
bool set_doc_content = CBLDocument_SetJSON(doc, json, &error);
114+
assert(set_doc_content);
115+
116+
FLMutableDict properties = CBLDocument_MutableProperties(doc);
117+
FLMutableDict_SetString(properties, FLSTR("owner"), FLSTR("00102204"));
118+
119+
bool saved = CBLDatabase_SaveDocument(db, doc, &error);
120+
assert(saved);
121+
122+
CBLDocument_Release(doc);
123+
}
124+
125+
free(json_format);
126+
}
67127

68-
bool array_index_created = CBLCollection_CreateArrayIndex(
69-
default_collection,
70-
FLSTR("one_level"),
71-
array_index_config,
128+
void getRemainingDocuments(CBLDatabase *db, FLString* result, int* count) {
129+
CBLError error;
130+
int errorPos = 0;
131+
CBLQuery* query = CBLDatabase_CreateQuery(
132+
db,
133+
kCBLN1QLLanguage,
134+
FLSTR("SELECT meta().id FROM _ WHERE _.type='ReplicationIssue' LIMIT 10"),
135+
&errorPos,
72136
&error
73137
);
74-
assert(array_index_created);
138+
assert(query);
139+
140+
CBLResultSet* queryResult = CBLQuery_Execute(query, &error);
141+
assert(queryResult);
142+
143+
int i = 0;
144+
while (CBLResultSet_Next(queryResult) && i < 10) {
145+
FLValue id = CBLResultSet_ValueAtIndex(queryResult, 0);
146+
result[i++] = FLSliceResult_AsSlice(FLSlice_Copy(FLValue_AsString(id)));
147+
}
148+
*count = i;
149+
150+
CBLResultSet_Release(queryResult);
151+
CBLQuery_Release(query);
152+
}
75153

76-
int error_pos = 0;
154+
int getDocumentCount(CBLDatabase *db) {
155+
CBLError error;
156+
int errorPos = 0;
77157
CBLQuery* query = CBLDatabase_CreateQuery(
78158
db,
79159
kCBLN1QLLanguage,
80-
FLSTR("SELECT _.name, _like FROM _ UNNEST _.likes as _like WHERE _like = 'travel'"),
81-
&error_pos,
160+
FLSTR("SELECT COUNT(*) FROM _ WHERE _.type='ReplicationIssue'"),
161+
&errorPos,
82162
&error
83163
);
84164
assert(query);
85165

86-
FLSliceResult explain_result = CBLQuery_Explain(query);
87-
assert(strstr(explain_result.buf, "USING INDEX one_level"));
166+
CBLResultSet* queryResult = CBLQuery_Execute(query, &error);
167+
assert(queryResult);
88168

89-
CBLResultSet* query_result = CBLQuery_Execute(query, &error);
90-
assert(query_result);
169+
assert(CBLResultSet_Next(queryResult));
170+
FLValue count = CBLResultSet_ValueAtIndex(queryResult, 0);
91171

92-
assert(CBLResultSet_Next(query_result));
172+
int result = FLValue_AsInt(count);
93173

94-
FLArray row = CBLResultSet_ResultArray(query_result);
95-
FLValue name = FLArray_Get(row, 0);
96-
assert(strcmp(FLValue_AsString(name).buf, "Sam") == 0);
174+
CBLResultSet_Release(queryResult);
175+
CBLQuery_Release(query);
97176

98-
assert(!CBLResultSet_Next(query_result));
177+
return result;
178+
}
99179

100-
CBLResultSet_Release(query_result);
101-
CBLQuery_Release(query);
180+
void deleteDocuments(CBLDatabase *db) {
181+
bool remaining = true;
182+
CBLError error;
102183

103-
// Complex array index
104-
array_index_config.expressionLanguage = kCBLN1QLLanguage;
105-
array_index_config.path = FLSTR("contacts[].phones");
106-
array_index_config.expressions = FLSTR("type");
184+
while (remaining) {
185+
sleep(1);
107186

108-
array_index_created = CBLCollection_CreateArrayIndex(
109-
default_collection,
110-
FLSTR("two_level"),
111-
array_index_config,
112-
&error
113-
);
114-
assert(array_index_created);
187+
FLString documents[10];
188+
int count = 0;
189+
getRemainingDocuments(db, documents, &count);
115190

116-
query = CBLDatabase_CreateQuery(
117-
db,
118-
kCBLN1QLLanguage,
119-
FLSTR("SELECT _.name, contact.type, phone.number FROM _ UNNEST _.contacts as contact UNNEST contact.phones as phone WHERE phone.type = 'mobile'"),
120-
&error_pos,
121-
&error
122-
);
123-
assert(query);
191+
remaining = (count > 0);
124192

125-
explain_result = CBLQuery_Explain(query);
126-
assert(strstr(explain_result.buf, "USING INDEX two_level"));
193+
for (int i = 0; i < count; i++) {
194+
const CBLDocument* doc = CBLDatabase_GetDocument(db, documents[i], &error);
195+
if (doc) {
196+
bool deleted = CBLDatabase_DeleteDocument(db, doc, &error);
197+
assert(deleted);
198+
CBLDocument_Release(doc);
199+
}
200+
}
201+
}
202+
}
127203

128-
query_result = CBLQuery_Execute(query, &error);
129-
assert(query_result);
204+
int main(void) {
205+
CBLConsoleLogSink log_sink = {};
206+
log_sink.level = kCBLLogDebug;
207+
log_sink.domains = kCBLLogDomainMaskAll;
130208

131-
assert(CBLResultSet_Next(query_result));
209+
CBLLogSinks_SetConsole(log_sink);
132210

133-
row = CBLResultSet_ResultArray(query_result);
134-
name = FLArray_Get(row, 0);
135-
assert(strcmp(FLValue_AsString(name).buf, "Sam") == 0);
211+
// Step configuration
212+
bool writer = false;
213+
bool deleter = false;
136214

137-
assert(CBLResultSet_Next(query_result));
138-
assert(!CBLResultSet_Next(query_result));
215+
FLSlice databaseName = writer || deleter ? FLSTR("writer") : FLSTR("observer");
139216

140-
CBLResultSet_Release(query_result);
141-
CBLQuery_Release(query);
217+
// Open database
218+
CBLError error;
219+
CBLDatabaseConfiguration config = {FLSTR("/Users/antoinemenciere/Documents")};
220+
CBLDatabase* db = CBLDatabase_Open(databaseName, &config, &error);
221+
assert(db);
142222

143-
// Cleanup
144-
bool closed = CBLDatabase_Delete(db, &error);
145-
assert(closed);
223+
// Start a replication
224+
startReplication(db, writer, deleter);
225+
226+
// Create 100 documents if the 'writer' variable is on
227+
if (writer) {
228+
printf("\nStart creating documents\n\n");
229+
createDocuments(db);
230+
printf("\nFinish creating documents\n\n");
231+
}
232+
233+
// Delete all documents if the 'deleter' variable is on
234+
if (deleter) {
235+
printf("\nStart deleting documents\n\n");
236+
deleteDocuments(db);
237+
printf("\nFinish deleting documents\n\n");
238+
}
239+
240+
// Always end by an infinite loop, to let the replication run as long as needed
241+
while (true) {
242+
sleep(1);
243+
244+
int count = getDocumentCount(db);
245+
printf("\nThere is %d document(s) in database\n\n", count);
246+
}
146247
}

0 commit comments

Comments
 (0)