mirror of
https://github.com/corda/corda.git
synced 2025-01-31 16:35:43 +00:00
Export attachment count via JMX
This commit is contained in:
parent
730b7949ea
commit
28869ad85d
@ -211,6 +211,6 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
|||||||
Files.createDirectory(attachmentsDir)
|
Files.createDirectory(attachmentsDir)
|
||||||
} catch (e: FileAlreadyExistsException) {
|
} catch (e: FileAlreadyExistsException) {
|
||||||
}
|
}
|
||||||
return NodeAttachmentService(attachmentsDir)
|
return NodeAttachmentService(attachmentsDir, services.monitoringService.metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
package core.node.services
|
package core.node.services
|
||||||
|
|
||||||
|
import com.codahale.metrics.MetricRegistry
|
||||||
import com.google.common.annotations.VisibleForTesting
|
import com.google.common.annotations.VisibleForTesting
|
||||||
import com.google.common.hash.Hashing
|
import com.google.common.hash.Hashing
|
||||||
import com.google.common.hash.HashingInputStream
|
import com.google.common.hash.HashingInputStream
|
||||||
@ -31,12 +32,21 @@ import javax.annotation.concurrent.ThreadSafe
|
|||||||
* Stores attachments in the specified local directory, which must exist. Doesn't allow new attachments to be uploaded.
|
* Stores attachments in the specified local directory, which must exist. Doesn't allow new attachments to be uploaded.
|
||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
class NodeAttachmentService(val storePath: Path) : AttachmentStorage, AcceptsFileUpload {
|
class NodeAttachmentService(val storePath: Path, val metrics: MetricRegistry) : AttachmentStorage, AcceptsFileUpload {
|
||||||
private val log = loggerFor<NodeAttachmentService>()
|
private val log = loggerFor<NodeAttachmentService>()
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
var checkAttachmentsOnLoad = true
|
var checkAttachmentsOnLoad = true
|
||||||
|
|
||||||
|
private val attachmentCount = metrics.counter("Attachments")
|
||||||
|
|
||||||
|
init {
|
||||||
|
attachmentCount.inc(countAttachments())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just count all non-directories in the attachment store, and assume the admin hasn't dumped any junk there.
|
||||||
|
private fun countAttachments() = Files.list(storePath).filter { Files.isRegularFile(it) }.count()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, newly inserted attachments will be unzipped to a subdirectory of the [storePath]. This is intended for
|
* If true, newly inserted attachments will be unzipped to a subdirectory of the [storePath]. This is intended for
|
||||||
* human browsing convenience: the attachment itself will still be the file (that is, edits to the extracted directory
|
* human browsing convenience: the attachment itself will still be the file (that is, edits to the extracted directory
|
||||||
@ -77,22 +87,25 @@ class NodeAttachmentService(val storePath: Path) : AttachmentStorage, AcceptsFil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openAttachment(id: SecureHash): Attachment? {
|
// Deliberately not an inner class to avoid holding a reference to the attachments service.
|
||||||
val path = storePath.resolve(id.toString())
|
private class AttachmentImpl(override val id: SecureHash,
|
||||||
if (!Files.exists(path)) return null
|
private val path: Path,
|
||||||
return object : Attachment {
|
private val checkOnLoad: Boolean) : Attachment {
|
||||||
override fun open(): InputStream {
|
override fun open(): InputStream {
|
||||||
var stream = Files.newInputStream(path)
|
var stream = Files.newInputStream(path)
|
||||||
// This is just an optional safety check. If it slows things down too much it can be disabled.
|
// This is just an optional safety check. If it slows things down too much it can be disabled.
|
||||||
if (id is SecureHash.SHA256 && checkAttachmentsOnLoad)
|
if (id is SecureHash.SHA256 && checkOnLoad)
|
||||||
stream = HashCheckingStream(id, path, stream)
|
stream = HashCheckingStream(id, path, stream)
|
||||||
log.debug("Opening attachment $id")
|
|
||||||
return stream
|
return stream
|
||||||
}
|
}
|
||||||
override val id: SecureHash = id
|
|
||||||
override fun equals(other: Any?) = other is Attachment && other.id == id
|
override fun equals(other: Any?) = other is Attachment && other.id == id
|
||||||
override fun hashCode(): Int = id.hashCode()
|
override fun hashCode(): Int = id.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openAttachment(id: SecureHash): Attachment? {
|
||||||
|
val path = storePath.resolve(id.toString())
|
||||||
|
if (!Files.exists(path)) return null
|
||||||
|
return AttachmentImpl(id, path, checkAttachmentsOnLoad)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun importAttachment(jar: InputStream): SecureHash {
|
override fun importAttachment(jar: InputStream): SecureHash {
|
||||||
@ -106,10 +119,12 @@ class NodeAttachmentService(val storePath: Path) : AttachmentStorage, AcceptsFil
|
|||||||
try {
|
try {
|
||||||
// Move into place atomically or fail if that isn't possible. We don't want a half moved attachment to
|
// Move into place atomically or fail if that isn't possible. We don't want a half moved attachment to
|
||||||
// be exposed to parallel threads. This gives us thread safety.
|
// be exposed to parallel threads. This gives us thread safety.
|
||||||
if (!Files.exists(finalPath))
|
if (!Files.exists(finalPath)) {
|
||||||
log.info("Stored new attachment $id")
|
log.info("Stored new attachment $id")
|
||||||
else
|
attachmentCount.inc()
|
||||||
|
} else {
|
||||||
log.info("Replacing attachment $id - only bother doing this if you're trying to repair file corruption")
|
log.info("Replacing attachment $id - only bother doing this if you're trying to repair file corruption")
|
||||||
|
}
|
||||||
Files.move(tmp, finalPath, StandardCopyOption.ATOMIC_MOVE)
|
Files.move(tmp, finalPath, StandardCopyOption.ATOMIC_MOVE)
|
||||||
} finally {
|
} finally {
|
||||||
Files.deleteIfExists(tmp)
|
Files.deleteIfExists(tmp)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
package core.node
|
package core.node
|
||||||
|
|
||||||
|
import com.codahale.metrics.MetricRegistry
|
||||||
import com.google.common.jimfs.Configuration
|
import com.google.common.jimfs.Configuration
|
||||||
import com.google.common.jimfs.Jimfs
|
import com.google.common.jimfs.Jimfs
|
||||||
import core.crypto.SecureHash
|
import core.crypto.SecureHash
|
||||||
@ -40,7 +41,7 @@ class NodeAttachmentStorageTest {
|
|||||||
val testJar = makeTestJar()
|
val testJar = makeTestJar()
|
||||||
val expectedHash = SecureHash.sha256(Files.readAllBytes(testJar))
|
val expectedHash = SecureHash.sha256(Files.readAllBytes(testJar))
|
||||||
|
|
||||||
val storage = NodeAttachmentService(fs.getPath("/"))
|
val storage = NodeAttachmentService(fs.getPath("/"), MetricRegistry())
|
||||||
val id = testJar.use { storage.importAttachment(it) }
|
val id = testJar.use { storage.importAttachment(it) }
|
||||||
assertEquals(expectedHash, id)
|
assertEquals(expectedHash, id)
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ class NodeAttachmentStorageTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `duplicates not allowed`() {
|
fun `duplicates not allowed`() {
|
||||||
val testJar = makeTestJar()
|
val testJar = makeTestJar()
|
||||||
val storage = NodeAttachmentService(fs.getPath("/"))
|
val storage = NodeAttachmentService(fs.getPath("/"), MetricRegistry())
|
||||||
testJar.use { storage.importAttachment(it) }
|
testJar.use { storage.importAttachment(it) }
|
||||||
assertFailsWith<java.nio.file.FileAlreadyExistsException> {
|
assertFailsWith<java.nio.file.FileAlreadyExistsException> {
|
||||||
testJar.use { storage.importAttachment(it) }
|
testJar.use { storage.importAttachment(it) }
|
||||||
@ -67,7 +68,7 @@ class NodeAttachmentStorageTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `corrupt entry throws exception`() {
|
fun `corrupt entry throws exception`() {
|
||||||
val testJar = makeTestJar()
|
val testJar = makeTestJar()
|
||||||
val storage = NodeAttachmentService(fs.getPath("/"))
|
val storage = NodeAttachmentService(fs.getPath("/"), MetricRegistry())
|
||||||
val id = testJar.use { storage.importAttachment(it) }
|
val id = testJar.use { storage.importAttachment(it) }
|
||||||
|
|
||||||
// Corrupt the file in the store.
|
// Corrupt the file in the store.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user