Skip to content

Commit 105b805

Browse files
committed
close writer before soft-deletione
1 parent d8c828c commit 105b805

File tree

6 files changed

+85
-27
lines changed

6 files changed

+85
-27
lines changed

src/main/scala/com/cloudant/clouseau/ClouseauTypeFactory.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ case class SearchRequest(options: Map[Symbol, Any])
3030

3131
case class OpenIndexMsg(peer: Pid, path: String, options: Any)
3232
case class CleanupPathMsg(path: String)
33-
case class RenamePathMsg(dbName: String)
3433
case class CleanupDbMsg(dbName: String, activeSigs: List[String])
3534
case class DiskSizeMsg(path: String)
35+
case class SoftDeletePathMsg(path: String)
3636

3737
case class Group1Msg(query: String, field: String, refresh: Boolean, groupSort: Any, groupOffset: Int,
3838
groupLimit: Int)
@@ -54,8 +54,6 @@ object ClouseauTypeFactory extends TypeFactory {
5454
Some(OpenIndexMsg(reader.readAs[Pid], reader.readAs[String], reader.readTerm))
5555
case ('cleanup, 2) =>
5656
Some(CleanupPathMsg(reader.readAs[String]))
57-
case ('rename, 2) =>
58-
Some(RenamePathMsg(reader.readAs[String]))
5957
case ('cleanup, 3) =>
6058
Some(CleanupDbMsg(reader.readAs[String], reader.readAs[List[String]]))
6159
case ('search, 2) =>
@@ -92,6 +90,8 @@ object ClouseauTypeFactory extends TypeFactory {
9290
Some(DeleteDocMsg(reader.readAs[String]))
9391
case ('disk_size, 2) =>
9492
Some(DiskSizeMsg(reader.readAs[String]))
93+
case ('soft_delete, 2) =>
94+
Some(SoftDeletePathMsg(reader.readAs[String]))
9595
case ('commit, 2) =>
9696
Some(CommitMsg(toLong(reader.readTerm)))
9797
case ('set_update_seq, 2) =>

src/main/scala/com/cloudant/clouseau/IndexCleanupService.scala

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ package com.cloudant.clouseau
1515
import com.yammer.metrics.scala._
1616
import java.io.File
1717
import java.util.regex.Pattern
18-
import java.text.SimpleDateFormat
19-
import java.util.Calendar
20-
import java.util.TimeZone
2118
import org.apache.log4j.Logger
2219
import scalang._
2320

@@ -31,19 +28,10 @@ class IndexCleanupService(ctx: ServiceContext[ConfigurationArgs]) extends Servic
3128
val dir = new File(rootDir, path)
3229
logger.info("Removing %s".format(path))
3330
recursivelyDelete(dir)
34-
case RenamePathMsg(dbName: String) =>
35-
val srcDir = new File(rootDir, dbName)
36-
val sdf = new SimpleDateFormat("yyyyMMdd'.'HHmmss")
37-
sdf.setTimeZone(TimeZone.getTimeZone("UTC"))
38-
val sdfNow = sdf.format(Calendar.getInstance().getTime())
39-
// move timestamp information in dbName to end of destination path
40-
// for example, from foo.1234567890 to foo.20170912.092828.deleted.1234567890
41-
val destPath = dbName.dropRight(10) + sdfNow + ".deleted." + dbName.takeRight(10)
42-
val destDir = new File(rootDir, destPath)
43-
logger.info("Renaming '%s' to '%s'".format(
44-
srcDir.getAbsolutePath, destDir.getAbsolutePath)
45-
)
46-
rename(srcDir, destDir)
31+
case SoftDeletePathMsg(path: String) =>
32+
logger.info("Soft-deleting " + path)
33+
val pattern = Pattern.compile(path + "/([0-9a-f]+)$")
34+
softDelete(rootDir, path, pattern)
4735
case CleanupDbMsg(dbName: String, activeSigs: List[String]) =>
4836
logger.info("Cleaning up " + dbName)
4937
val pattern = Pattern.compile("shards/[0-9a-f]+-[0-9a-f]+/" + dbName + "\\.[0-9]+/([0-9a-f]+)$")
@@ -78,13 +66,24 @@ class IndexCleanupService(ctx: ServiceContext[ConfigurationArgs]) extends Servic
7866
fileOrDir.delete
7967
}
8068

81-
private def rename(srcDir: File, destDir: File) {
82-
if (!srcDir.isDirectory) {
69+
private def softDelete(fileOrDir: File, path: String, includePattern: Pattern) {
70+
if (!fileOrDir.isDirectory) {
8371
return
8472
}
85-
if (!srcDir.renameTo(destDir)) {
86-
logger.error("Failed to rename directory from '%s' to '%s'".format(
87-
srcDir.getAbsolutePath, destDir.getAbsolutePath))
73+
for (file <- fileOrDir.listFiles) {
74+
softDelete(file, path, includePattern)
75+
}
76+
77+
logger.info(fileOrDir.getAbsolutePath)
78+
val m = includePattern.matcher(fileOrDir.getAbsolutePath)
79+
if (m.find) {
80+
logger.info("Soft-deleting index " + m.group)
81+
call('main, ('soft_delete, m.group)) match {
82+
case 'ok =>
83+
'ok
84+
case ('error, 'not_found) =>
85+
Utils.rename(rootDir, path, fileOrDir.getName)
86+
}
8887
}
8988
}
9089

src/main/scala/com/cloudant/clouseau/IndexManagerService.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ class IndexManagerService(ctx: ServiceContext[ConfigurationArgs]) extends Servic
119119
pid ! 'delete
120120
'ok
121121
}
122+
case ('soft_delete, path: String) =>
123+
lru.get(path) match {
124+
case null =>
125+
('error, 'not_found)
126+
case pid: Pid =>
127+
pid ! 'soft_delete
128+
'ok
129+
}
122130
case DiskSizeMsg(path: String) =>
123131
getDiskSize(path)
124132
case 'close_lru =>

src/main/scala/com/cloudant/clouseau/IndexService.scala

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,13 @@ class IndexService(ctx: ServiceContext[IndexServiceArgs]) extends Service(ctx) w
178178
dir.deleteFile(name)
179179
}
180180
exit('deleted)
181+
case 'soft_delete =>
182+
ctx.args.writer.close()
183+
val rootDir = new File(ctx.args.config.getString("clouseau.dir", "target/indexes"))
184+
val path = ctx.args.name.substring(0, ctx.args.name.lastIndexOf('/'))
185+
val sig = ctx.args.name.substring(ctx.args.name.lastIndexOf('/') + 1)
186+
Utils.rename(rootDir, path, sig)
187+
exit('deleted)
181188
case 'maybe_commit =>
182189
commit(pendingSeq, pendingPurgeSeq)
183190
case ('committed, newUpdateSeq: Long, newPurgeSeq: Long) =>
@@ -220,7 +227,16 @@ class IndexService(ctx: ServiceContext[IndexServiceArgs]) extends Service(ctx) w
220227
ctx.args.writer.rollback()
221228
} catch {
222229
case e: AlreadyClosedException => 'ignored
223-
case e: IOException => warn("Error while closing writer", e)
230+
case e: IOException =>
231+
try {
232+
ctx.args.writer.close();
233+
} finally {
234+
val dir = ctx.args.writer.getDirectory
235+
if (IndexWriter.isLocked(dir)) {
236+
IndexWriter.unlock(dir);
237+
}
238+
}
239+
warn("Error while closing writer", e)
224240
} finally {
225241
super.exit(msg)
226242
}

src/main/scala/com/cloudant/clouseau/Utils.scala

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ package com.cloudant.clouseau
1515
import org.apache.lucene.index.Term
1616
import org.apache.lucene.util.BytesRef
1717
import org.apache.lucene.util.NumericUtils
18+
import org.apache.log4j.Logger
19+
import java.io.File
20+
import java.io.IOException
21+
import java.util.Calendar
22+
import java.util.TimeZone
23+
import java.text.SimpleDateFormat
1824

1925
object Utils {
2026

@@ -29,4 +35,33 @@ object Utils {
2935
new BytesRef(string)
3036
}
3137

38+
def rename(rootDir: File, dbName: String, sig: String) {
39+
val logger = Logger.getLogger("clouseau.utils")
40+
val srcParentDir = new File(rootDir, dbName)
41+
val sdf = new SimpleDateFormat("yyyyMMdd'.'HHmmss")
42+
sdf.setTimeZone(TimeZone.getTimeZone("UTC"))
43+
val sdfNow = sdf.format(Calendar.getInstance().getTime())
44+
// move timestamp information in dbName to end of destination path
45+
// for example, from foo.1234567890 to foo.20170912.092828.deleted.1234567890
46+
val destParentPath = dbName.dropRight(10) + sdfNow + ".deleted." + dbName.takeRight(10)
47+
val destParentDir = new File(rootDir, destParentPath)
48+
logger.info("Renaming '%s' to '%s'".format(
49+
srcParentDir.getAbsolutePath, destParentDir.getAbsolutePath)
50+
)
51+
if (!srcParentDir.isDirectory) {
52+
return
53+
}
54+
if (!destParentDir.exists) {
55+
destParentDir.mkdirs
56+
}
57+
58+
val srcDir = new File(srcParentDir, sig)
59+
val destDir = new File(destParentDir, sig)
60+
61+
if (!srcDir.renameTo(destDir)) {
62+
logger.error("Failed to rename directory from '%s' to '%s'".format(
63+
srcDir.getAbsolutePath, destDir.getAbsolutePath))
64+
}
65+
}
66+
3267
}

src/test/scala/com/cloudant/clouseau/IndexCleanupServiceSpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ class IndexCleanupServiceSpec extends SpecificationWithJUnit {
2222

2323
"the index clean-up service" should {
2424

25-
"rename index when database is deleted" in new cleanup_service {
26-
node.cast(service, RenamePathMsg("foo.1234567890")) must be equalTo 'ok
25+
"soft-delete index when database is deleted" in new cleanup_service {
26+
node.cast(service, SoftDeletePathMsg("foo.1234567890")) must be equalTo 'ok
2727
Thread.sleep(1000)
2828
val indexdir = new File("target", "indexes")
2929
var subdirlist = List[String]()

0 commit comments

Comments
 (0)