Skip to content

Commit c6e8d2c

Browse files
author
Hideki Itakura
committed
Merge branch 'release/1.1.0'
* release/1.1.0: (24 commits) - return false in case of any error during database initialization - remove unnecessary cursor close code Fixed #607 - Apply transaction for database initialization. Just removed debugging code Applied java coding style Fixed #596 Applied @pasin 's feedback https://github.com/couchbase/couchbase-lite-java-core/pull/605/files#r29380839 attachment folder and its parent folder should be deleted separately. delete obsoleted file path Check if directory exists before calling mkdir() method Fixed #604 - Attachments folder path is not compatible with iOS Use `private` instead of `public`. Fixed #602 Make / db names work in windows Removed Replicator.ChangeListener - Apply synchronized - Changed Log.e(), Log.w(), and Log.i() to Log.d() for non-error cases Fixed #575 Fixed #456 Fixed #590 Fixed CBL Android 210 - Heavy memory usage causes the null field return value for SQL query. It causes the missing index. Applied the feedback from @pasin - convert from digest to blob key could fail, for example, digest is md5-xxxx. ...
2 parents 1e671f4 + 8f7790e commit c6e8d2c

8 files changed

Lines changed: 631 additions & 355 deletions

File tree

src/main/java/com/couchbase/lite/BlobStore.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ public BlobStore(String path, boolean autoMigrate) {
5656
this.path = path;
5757
File directory = new File(path);
5858

59-
directory.mkdirs();
59+
if (!directory.exists()) {
60+
directory.mkdirs();
61+
}
6062
if (!directory.isDirectory()) {
6163
throw new IllegalStateException(String.format("Unable to create directory for: %s", directory));
6264
}
@@ -173,6 +175,12 @@ public boolean getKeyForFilename(BlobKey outKey, String filename) {
173175
return true;
174176
}
175177

178+
public boolean hasBlobForKey(BlobKey key){
179+
String path = pathForKey(key);
180+
File file = new File(path);
181+
return file.isFile() && file.exists();
182+
}
183+
176184
public byte[] blobForKey(BlobKey key) {
177185
String path = pathForKey(key);
178186
File file = new File(path);
@@ -369,7 +377,9 @@ public File tempDir() {
369377
File directory = new File(path);
370378
File tempDirectory = new File(directory, "temp_attachments");
371379

372-
tempDirectory.mkdirs();
380+
if (!tempDirectory.exists()) {
381+
tempDirectory.mkdirs();
382+
}
373383
if (!tempDirectory.isDirectory()) {
374384
throw new IllegalStateException(String.format("Unable to create directory for: %s", tempDirectory));
375385
}

src/main/java/com/couchbase/lite/Database.java

Lines changed: 433 additions & 223 deletions
Large diffs are not rendered by default.

src/main/java/com/couchbase/lite/Manager.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import com.couchbase.lite.support.Version;
1111
import com.couchbase.lite.util.Log;
1212
import com.couchbase.lite.util.StreamUtils;
13-
1413
import com.couchbase.lite.util.Utils;
1514
import com.fasterxml.jackson.databind.ObjectMapper;
1615

@@ -130,7 +129,9 @@ public Manager(Context context, ManagerOptions options) throws IOException {
130129
this.databases = new HashMap<String, Database>();
131130
this.replications = new ArrayList<Replication>();
132131

133-
directoryFile.mkdirs();
132+
if (!directoryFile.exists()) {
133+
directoryFile.mkdirs();
134+
}
134135
if (!directoryFile.isDirectory()) {
135136
throw new IOException(String.format("Unable to create directory for: %s", directoryFile));
136137
}
@@ -289,7 +290,9 @@ private void replaceDatabase(String databaseName, InputStream databaseStream, It
289290
StreamUtils.copyStream(databaseStream, destStream);
290291
File attachmentsFile = new File(dstAttachmentsPath);
291292
FileDirUtils.deleteRecursive(attachmentsFile);
292-
attachmentsFile.mkdirs();
293+
if (!attachmentsFile.exists()) {
294+
attachmentsFile.mkdirs();
295+
}
293296
if (attachmentStreams != null) {
294297
StreamUtils.copyStreamsToFolder(attachmentStreams, attachmentsFile);
295298
}
@@ -417,7 +420,14 @@ private String pathForName(String name) {
417420
if ((name == null) || (name.length() == 0) || Pattern.matches(LEGAL_CHARACTERS, name)) {
418421
return null;
419422
}
420-
name = name.replace('/', ':');
423+
// NOTE: CouchDB allows forward slash as part of database name.
424+
// However, ':' is illegal character on Windows platform.
425+
// For Windows, substitute with period '.'
426+
if(isWindows()) {
427+
name = name.replace('/', '.');
428+
}else{
429+
name = name.replace('/', ':');
430+
}
421431
String result = directoryFile.getPath() + File.separator + name + Manager.DATABASE_SUFFIX;
422432
return result;
423433
}
@@ -668,5 +678,15 @@ public Context getContext() {
668678
protected boolean isAutoMigrateBlobStoreFilename() {
669679
return this.options.isAutoMigrateBlobStoreFilename();
670680
}
681+
682+
private static String OS = System.getProperty("os.name").toLowerCase();
683+
684+
/**
685+
* Check if platform is Windows
686+
*/
687+
@InterfaceAudience.Private
688+
private static boolean isWindows() {
689+
return (OS.indexOf("win") >= 0);
690+
}
671691
}
672692

src/main/java/com/couchbase/lite/View.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -512,9 +512,16 @@ public void emit(Object key, Object value) {
512512
}
513513
};
514514

515-
// Now scan every revision added since the last time the view was
516-
// indexed:
517-
StringBuffer sql = new StringBuffer( "SELECT revs.doc_id, sequence, docid, revid, json, no_attachments, deleted FROM revs, docs WHERE sequence>? AND current!=0 ");
515+
// Now scan every revision added since the last time the view was indexed:
516+
517+
// NOTE: Below is original Query. In case query result uses a lot of memory,
518+
// Android SQLiteDatabase causes null value column. Then it causes the missing
519+
// index data because following logic skip result if column is null.
520+
// To avoid the issue, retrieving json field is isolated from original query.
521+
// Because json field could be large, maximum size is 2MB.
522+
// StringBuffer sql = new StringBuffer( "SELECT revs.doc_id, sequence, docid, revid, json, no_attachments, deleted FROM revs, docs WHERE sequence>? AND current!=0 ");
523+
524+
StringBuffer sql = new StringBuffer( "SELECT revs.doc_id, sequence, docid, revid, no_attachments, deleted FROM revs, docs WHERE sequence>? AND current!=0 ");
518525
if(minLastSequence == 0) {
519526
sql.append("AND deleted=0 ");
520527
}
@@ -542,10 +549,9 @@ public void emit(Object key, Object value) {
542549
continue;
543550
}
544551
String revId = cursor.getString(3);
545-
byte[] json = cursor.getBlob(4);
546552

547-
boolean noAttachments = cursor.getInt(5) > 0;
548-
boolean deleted = cursor.getInt(6) > 0;
553+
boolean noAttachments = cursor.getInt(4) > 0;
554+
boolean deleted = cursor.getInt(5) > 0;
549555

550556
while ((keepGoing = cursor.moveToNext()) && (cursor.isNull(0) || cursor.getLong(0) == docID)) {
551557
// Skip rows with the same doc_id -- these are losing conflicts.
@@ -583,8 +589,6 @@ public void emit(Object key, Object value) {
583589
revId = oldRevId;
584590
sequence = oldSequence;
585591
deleted = false;
586-
String[] selectArgs3 = { Long.toString(sequence) };
587-
json = Utils.byteArrayResultForQuery(database.getDatabase(), "SELECT json FROM revs WHERE sequence=?", selectArgs3);
588592
}
589593
}
590594
} finally {
@@ -598,6 +602,9 @@ public void emit(Object key, Object value) {
598602
continue;
599603
}
600604

605+
String[] selectArgs3 = { Long.toString(sequence) };
606+
byte[] json = Utils.byteArrayResultForQuery(database.getDatabase(), "SELECT json FROM revs WHERE sequence=?", selectArgs3);
607+
601608
// Get the document properties, to pass to the map function:
602609
EnumSet<TDContentOptions> contentOptions = EnumSet.noneOf(Database.TDContentOptions.class);
603610
if (noAttachments)
@@ -615,7 +622,11 @@ public void emit(Object key, Object value) {
615622
// pairs from this revision:
616623
emitBlock.setSequence(sequence);
617624
mapBlock.map(properties, emitBlock);
625+
626+
properties.clear();
627+
properties = null;
618628
}
629+
json = null;
619630
}
620631

621632
// Finally, record the last revision sequence number that was

src/main/java/com/couchbase/lite/replicator/ChangeTracker.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public void setAuthenticator(Authenticator authenticator) {
217217

218218
@Override
219219
public void run() {
220-
Log.e(Log.TAG_CHANGE_TRACKER, "Thread id => " + Thread.currentThread().getId());
220+
Log.d(Log.TAG_CHANGE_TRACKER, "Thread id => " + Thread.currentThread().getId());
221221
try {
222222
runLoop();
223223
} finally {
@@ -357,7 +357,7 @@ public void process(HttpRequest request, HttpContext context) throws HttpExcepti
357357
backoff.resetBackoff();
358358
continue;
359359
} else {
360-
Log.w(Log.TAG_CHANGE_TRACKER, "%s: Change tracker calling stop (LongPoll)", this);
360+
Log.d(Log.TAG_CHANGE_TRACKER, "%s: Change tracker calling stop (LongPoll)", this);
361361
client.changeTrackerFinished(this);
362362
break;
363363
}
@@ -389,7 +389,7 @@ public void process(HttpRequest request, HttpContext context) throws HttpExcepti
389389
if (isContinuous()) { // if enclosing replication is continuous
390390
mode = ChangeTrackerMode.LongPoll;
391391
} else {
392-
Log.w(Log.TAG_CHANGE_TRACKER, "%s: Change tracker calling stop (OneShot)", this);
392+
Log.d(Log.TAG_CHANGE_TRACKER, "%s: Change tracker calling stop (OneShot)", this);
393393
client.changeTrackerFinished(this);
394394
break;
395395
}
@@ -496,10 +496,10 @@ public void stop() {
496496
private void stopped() {
497497
Log.d(Log.TAG_CHANGE_TRACKER, "%s: Change tracker in stopped()", this);
498498
if (client != null) {
499-
Log.w(Log.TAG_CHANGE_TRACKER, "%s: Change tracker calling changeTrackerStopped, client: %s", this, client);
499+
Log.d(Log.TAG_CHANGE_TRACKER, "%s: Change tracker calling changeTrackerStopped, client: %s", this, client);
500500
client.changeTrackerStopped(ChangeTracker.this);
501501
} else {
502-
Log.w(Log.TAG_CHANGE_TRACKER, "%s: Change tracker not calling changeTrackerStopped, client == null", this);
502+
Log.d(Log.TAG_CHANGE_TRACKER, "%s: Change tracker not calling changeTrackerStopped, client == null", this);
503503
}
504504
client = null;
505505
running = false; // in case stop() method was not called to stop

0 commit comments

Comments
 (0)