summaryrefslogtreecommitdiffstats
path: root/node-admin
diff options
context:
space:
mode:
authorValerij Fredriksen <valerijf@verizonmedia.com>2019-11-19 14:17:17 +0100
committerValerij Fredriksen <valerijf@verizonmedia.com>2019-11-19 14:17:17 +0100
commit5788a6e05d2e2cca27ff68a18399ce455594683d (patch)
treed809ea907b6f1a9b3a4258de5f1118cdc1b8d817 /node-admin
parent66d8f6ca659288176a7624c2b46c4ae0c064b779 (diff)
Allow modifying only content with FileSync
Diffstat (limited to 'node-admin')
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/AttributeSync.java7
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileAttributesCache.java32
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileContentCache.java3
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileSync.java43
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/MakeDirectory.java8
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileAttributesCacheTest.java7
6 files changed, 44 insertions, 56 deletions
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/AttributeSync.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/AttributeSync.java
index cba3912ce49..16eb1a9b509 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/AttributeSync.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/AttributeSync.java
@@ -1,5 +1,4 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
package com.yahoo.vespa.hosted.node.admin.task.util.file;
import com.yahoo.vespa.hosted.node.admin.component.TaskContext;
@@ -77,21 +76,21 @@ public class AttributeSync {
context,
"owner",
owner,
- () -> currentAttributes.get().owner(),
+ () -> currentAttributes.getOrThrow().owner(),
path::setOwner);
systemModified |= updateAttribute(
context,
"group",
group,
- () -> currentAttributes.get().group(),
+ () -> currentAttributes.getOrThrow().group(),
path::setGroup);
systemModified |= updateAttribute(
context,
"permissions",
permissions,
- () -> currentAttributes.get().permissions(),
+ () -> currentAttributes.getOrThrow().permissions(),
path::setPermissions);
return systemModified;
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileAttributesCache.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileAttributesCache.java
index 12a9609f89c..a35bc844b8f 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileAttributesCache.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileAttributesCache.java
@@ -1,5 +1,4 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
package com.yahoo.vespa.hosted.node.admin.task.util.file;
import java.util.Optional;
@@ -11,34 +10,23 @@ public class FileAttributesCache {
private Optional<FileAttributes> attributes = Optional.empty();
public FileAttributesCache(UnixPath path) {
- this.path = path;
+ this.path = path;
}
- public FileAttributes get() {
- if (!attributes.isPresent()) {
- attributes = Optional.of(path.getAttributes());
+ public Optional<FileAttributes> get() {
+ if (attributes.isEmpty()) {
+ attributes = path.getAttributesIfExists();
}
- return attributes.get();
+ return attributes;
}
- public FileAttributes forceGet() {
- attributes = Optional.empty();
- return get();
+ public FileAttributes getOrThrow() {
+ return get().orElseThrow();
}
- public boolean exists() {
- if (attributes.isPresent()) {
- return true;
- }
-
- Optional<FileAttributes> attributes = path.getAttributesIfExists();
- if (attributes.isPresent()) {
- // Might as well update this.attributes
- this.attributes = attributes;
- return true;
- } else {
- return false;
- }
+ public Optional<FileAttributes> forceGet() {
+ attributes = Optional.empty();
+ return get();
}
}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileContentCache.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileContentCache.java
index 43c9f7729ef..974ab68dc1c 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileContentCache.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileContentCache.java
@@ -1,5 +1,4 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
package com.yahoo.vespa.hosted.node.admin.task.util.file;
import java.time.Instant;
@@ -21,7 +20,7 @@ class FileContentCache {
}
byte[] get(Instant lastModifiedTime) {
- if (!value.isPresent() || lastModifiedTime.compareTo(modifiedTime.get()) > 0) {
+ if (modifiedTime.isEmpty() || lastModifiedTime.isAfter(modifiedTime.get())) {
value = Optional.of(path.readBytes());
modifiedTime = Optional.of(lastModifiedTime);
}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileSync.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileSync.java
index dc13ea1c9ab..7a11ecdf6ab 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileSync.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileSync.java
@@ -1,18 +1,14 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
package com.yahoo.vespa.hosted.node.admin.task.util.file;
import com.yahoo.vespa.hosted.node.admin.component.TaskContext;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
import java.nio.file.Path;
+import java.time.Instant;
import java.util.Arrays;
import java.util.Optional;
import java.util.logging.Logger;
-import static com.yahoo.yolean.Exceptions.uncheck;
-
/**
* Class to minimize resource usage with repetitive and mostly identical, idempotent, and
* mutating file operations, e.g. setting file content, setting owner, etc.
@@ -27,10 +23,12 @@ public class FileSync {
private final UnixPath path;
private final FileContentCache contentCache;
+ private final FileAttributesCache attributesCache;
public FileSync(Path path) {
this.path = new UnixPath(path);
this.contentCache = new FileContentCache(this.path);
+ this.attributesCache = new FileAttributesCache(this.path);
}
public boolean convergeTo(TaskContext taskContext, PartialFileData partialFileData) {
@@ -46,38 +44,41 @@ public class FileSync {
* system is only modified if necessary (different).
*/
public boolean convergeTo(TaskContext taskContext, PartialFileData partialFileData, boolean atomicWrite) {
- FileAttributesCache currentAttributes = new FileAttributesCache(path);
+ boolean modifiedSystem = false;
- boolean modifiedSystem = maybeUpdateContent(taskContext, partialFileData.getContent(), currentAttributes, atomicWrite);
+ if (partialFileData.getContent().isPresent())
+ modifiedSystem |= convergeTo(taskContext, partialFileData.getContent().get(), atomicWrite);
AttributeSync attributeSync = new AttributeSync(path.toPath()).with(partialFileData);
- modifiedSystem |= attributeSync.converge(taskContext, currentAttributes);
+ modifiedSystem |= attributeSync.converge(taskContext, this.attributesCache);
return modifiedSystem;
}
- private boolean maybeUpdateContent(TaskContext taskContext,
- Optional<byte[]> content,
- FileAttributesCache currentAttributes,
- boolean atomicWrite) {
- if (!content.isPresent()) {
- return false;
- }
+ /**
+ * CPU, I/O, and memory usage is optimized for repeated calls with the same argument.
+ *
+ * @param atomicWrite Whether to write updates to a temporary file in the same directory, and atomically move it
+ * to path. Ensures the file cannot be read while in the middle of writing it.
+ * @return true if the content was written. Only modified if necessary (different).
+ */
+ public boolean convergeTo(TaskContext taskContext, byte[] content, boolean atomicWrite) {
+ Optional<Instant> lastModifiedTime = attributesCache.forceGet().map(FileAttributes::lastModifiedTime);
- if (!currentAttributes.exists()) {
+ if (lastModifiedTime.isEmpty()) {
taskContext.recordSystemModification(logger, "Creating file " + path);
path.createParents();
- writeBytes(content.get(), atomicWrite);
- contentCache.updateWith(content.get(), currentAttributes.forceGet().lastModifiedTime());
+ writeBytes(content, atomicWrite);
+ contentCache.updateWith(content, attributesCache.forceGet().orElseThrow().lastModifiedTime());
return true;
}
- if (Arrays.equals(content.get(), contentCache.get(currentAttributes.get().lastModifiedTime()))) {
+ if (Arrays.equals(content, contentCache.get(attributesCache.getOrThrow().lastModifiedTime()))) {
return false;
} else {
taskContext.recordSystemModification(logger, "Patching file " + path);
- writeBytes(content.get(), atomicWrite);
- contentCache.updateWith(content.get(), currentAttributes.forceGet().lastModifiedTime());
+ writeBytes(content, atomicWrite);
+ contentCache.updateWith(content, attributesCache.forceGet().orElseThrow().lastModifiedTime());
return true;
}
}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/MakeDirectory.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/MakeDirectory.java
index 5f72ed7e9b8..e2366470f61 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/MakeDirectory.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/MakeDirectory.java
@@ -19,12 +19,14 @@ public class MakeDirectory {
private final UnixPath path;
private final AttributeSync attributeSync;
+ private final FileAttributesCache attributesCache;
private boolean createParents = false;
public MakeDirectory(Path path) {
this.path = new UnixPath(path);
this.attributeSync = new AttributeSync(path);
+ this.attributesCache = new FileAttributesCache(this.path);
}
/**
@@ -42,8 +44,8 @@ public class MakeDirectory {
public boolean converge(TaskContext context) {
boolean systemModified = false;
- FileAttributesCache attributes = new FileAttributesCache(path);
- if (attributes.exists()) {
+ Optional<FileAttributes> attributes = attributesCache.forceGet();
+ if (attributes.isPresent()) {
if (!attributes.get().isDirectory()) {
throw new UncheckedIOException(new NotDirectoryException(path.toString()));
}
@@ -65,7 +67,7 @@ public class MakeDirectory {
}
}
- systemModified |= attributeSync.converge(context, attributes);
+ systemModified |= attributeSync.converge(context, attributesCache);
return systemModified;
}
diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileAttributesCacheTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileAttributesCacheTest.java
index 06192c9f308..88b33a7f9a8 100644
--- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileAttributesCacheTest.java
+++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/file/FileAttributesCacheTest.java
@@ -1,5 +1,4 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
package com.yahoo.vespa.hosted.node.admin.task.util.file;
import org.junit.Test;
@@ -22,17 +21,17 @@ public class FileAttributesCacheTest {
FileAttributesCache cache = new FileAttributesCache(unixPath);
when(unixPath.getAttributesIfExists()).thenReturn(Optional.empty());
- assertFalse(cache.exists());
+ assertFalse(cache.get().isPresent());
verify(unixPath, times(1)).getAttributesIfExists();
verifyNoMoreInteractions(unixPath);
FileAttributes attributes = mock(FileAttributes.class);
when(unixPath.getAttributesIfExists()).thenReturn(Optional.of(attributes));
- assertTrue(cache.exists());
+ assertTrue(cache.get().isPresent());
verify(unixPath, times(1 + 1)).getAttributesIfExists();
verifyNoMoreInteractions(unixPath);
- assertEquals(attributes, cache.get());
+ assertEquals(attributes, cache.getOrThrow());
verifyNoMoreInteractions(unixPath);
}
} \ No newline at end of file