-
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add SkipBloatUnderThresholdPredicate
- Loading branch information
Showing
5 changed files
with
160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
...src/main/java/io/github/mfvanek/pg/model/predicates/SkipBloatUnderThresholdPredicate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
* Copyright (c) 2019-2024. Ivan Vakhrushev and others. | ||
* https://github.com/mfvanek/pg-index-health | ||
* | ||
* This file is a part of "pg-index-health" - a Java library for | ||
* analyzing and maintaining indexes health in PostgreSQL databases. | ||
* | ||
* Licensed under the Apache License 2.0 | ||
*/ | ||
|
||
package io.github.mfvanek.pg.model.predicates; | ||
|
||
import io.github.mfvanek.pg.model.BloatAware; | ||
import io.github.mfvanek.pg.model.DbObject; | ||
import io.github.mfvanek.pg.model.validation.Validators; | ||
|
||
import java.util.function.Predicate; | ||
import javax.annotation.Nonnull; | ||
import javax.annotation.concurrent.Immutable; | ||
import javax.annotation.concurrent.ThreadSafe; | ||
|
||
/** | ||
* A predicate that filters out database objects with bloat values under specified thresholds. | ||
* Only database objects that implement {@link BloatAware} are evaluated, and they will be skipped if | ||
* their bloat size or percentage falls below the specified thresholds. | ||
* | ||
* @author Ivan Vakhrushev | ||
* @see Predicate | ||
* @see BloatAware | ||
* @since 0.13.3 | ||
*/ | ||
@Immutable | ||
@ThreadSafe | ||
public final class SkipBloatUnderThresholdPredicate implements Predicate<DbObject> { | ||
|
||
private final long sizeThresholdInBytes; | ||
private final double percentageThreshold; | ||
|
||
private SkipBloatUnderThresholdPredicate(final long sizeThresholdInBytes, final double percentageThreshold) { | ||
this.sizeThresholdInBytes = Validators.sizeNotNegative(sizeThresholdInBytes, "sizeThresholdInBytes"); | ||
this.percentageThreshold = Validators.validPercent(percentageThreshold, "percentageThreshold"); | ||
} | ||
|
||
/** | ||
* Tests whether the specified {@code DbObject} meets or exceeds the bloat thresholds. | ||
* <p> | ||
* If {@code dbObject} implements {@link BloatAware}, its bloat size and percentage are checked | ||
* against the thresholds. If {@code dbObject} does not implement {@link BloatAware}, it passes the test by default. | ||
* </p> | ||
* | ||
* @param dbObject the database object to test | ||
* @return {@code true} if the {@code dbObject} meets or exceeds the thresholds or does not implement {@link BloatAware}; {@code false} if it is below the thresholds | ||
*/ | ||
@Override | ||
public boolean test(@Nonnull final DbObject dbObject) { | ||
if (sizeThresholdInBytes == 0L && percentageThreshold == 0.0) { | ||
return true; | ||
} | ||
if (!(dbObject instanceof BloatAware)) { | ||
return true; | ||
} | ||
final BloatAware bloatAware = (BloatAware) dbObject; | ||
return bloatAware.getBloatSizeInBytes() >= sizeThresholdInBytes && | ||
bloatAware.getBloatPercentage() >= percentageThreshold; | ||
} | ||
|
||
/** | ||
* Creates a predicate to skip {@link BloatAware} objects with bloat below specified thresholds. | ||
* | ||
* @param sizeThresholdInBytes minimum bloat size in bytes required for a {@link BloatAware} object to pass the test; must be non-negative | ||
* @param percentageThreshold minimum bloat percentage required for a {@link BloatAware} object to pass the test; must be a valid percentage (0-100) | ||
* @return a {@link Predicate} that skips objects below the specified bloat thresholds | ||
*/ | ||
@Nonnull | ||
public static Predicate<DbObject> of(final long sizeThresholdInBytes, final double percentageThreshold) { | ||
return new SkipBloatUnderThresholdPredicate(sizeThresholdInBytes, percentageThreshold); | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
...test/java/io/github/mfvanek/pg/model/predicates/SkipBloatUnderThresholdPredicateTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Copyright (c) 2019-2024. Ivan Vakhrushev and others. | ||
* https://github.com/mfvanek/pg-index-health | ||
* | ||
* This file is a part of "pg-index-health" - a Java library for | ||
* analyzing and maintaining indexes health in PostgreSQL databases. | ||
* | ||
* Licensed under the Apache License 2.0 | ||
*/ | ||
|
||
package io.github.mfvanek.pg.model.predicates; | ||
|
||
import io.github.mfvanek.pg.model.index.IndexWithBloat; | ||
import io.github.mfvanek.pg.model.sequence.SequenceState; | ||
import io.github.mfvanek.pg.model.table.Table; | ||
import io.github.mfvanek.pg.model.table.TableWithBloat; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.Mockito; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
||
class SkipBloatUnderThresholdPredicateTest { | ||
|
||
@Test | ||
void shouldThrowExceptionWhenInvalidDataPassed() { | ||
assertThatThrownBy(() -> SkipBloatUnderThresholdPredicate.of(-1L, -1.0)) | ||
.isInstanceOf(IllegalArgumentException.class) | ||
.hasMessage("sizeThresholdInBytes cannot be less than zero"); | ||
|
||
assertThatThrownBy(() -> SkipBloatUnderThresholdPredicate.of(0L, -1.0)) | ||
.isInstanceOf(IllegalArgumentException.class) | ||
.hasMessage("percentageThreshold should be in the range from 0.0 to 100.0 inclusive"); | ||
|
||
assertThatThrownBy(() -> SkipBloatUnderThresholdPredicate.of(0L, 100.1)) | ||
.isInstanceOf(IllegalArgumentException.class) | ||
.hasMessage("percentageThreshold should be in the range from 0.0 to 100.0 inclusive"); | ||
} | ||
|
||
@Test | ||
void shouldNotCastObjectsWhenThresholdIsZero() { | ||
final TableWithBloat mockBloat = Mockito.mock(TableWithBloat.class); | ||
assertThat(SkipBloatUnderThresholdPredicate.of(0L, 0.0)) | ||
.accepts(mockBloat); | ||
Mockito.verify(mockBloat, Mockito.never()).getBloatPercentage(); | ||
Mockito.verify(mockBloat, Mockito.never()).getBloatSizeInBytes(); | ||
} | ||
|
||
@Test | ||
void shouldWork() { | ||
assertThat(SkipBloatUnderThresholdPredicate.of(100L, 10.0)) | ||
.accepts(Table.of("t", 0L)) | ||
.accepts(SequenceState.of("s1", "int", 80.0)) | ||
.rejects(TableWithBloat.of(Table.of("t2", 1L), 1L, 10.0)) | ||
.rejects(TableWithBloat.of(Table.of("t2", 1L), 1L, 11.0)) | ||
.accepts(TableWithBloat.of(Table.of("t2", 100L), 100L, 10.0)) | ||
.accepts(TableWithBloat.of(Table.of("t2", 200L), 101L, 10.0)) | ||
.rejects(IndexWithBloat.of("t2", "i2", 1L, 1L, 10.0)) | ||
.rejects(IndexWithBloat.of("t2", "i2", 1L, 1L, 11.0)) | ||
.accepts(IndexWithBloat.of("t2", "i2", 100L, 100L, 10.0)) | ||
.accepts(IndexWithBloat.of("t2", "i2", 200L, 101L, 10.0)); | ||
|
||
assertThat(SkipBloatUnderThresholdPredicate.of(0L, 1.0)) | ||
.rejects(TableWithBloat.of(Table.of("t2", 1L), 0L, 0.1)) | ||
.accepts(TableWithBloat.of(Table.of("t2", 100L), 1L, 1.0)); | ||
|
||
assertThat(SkipBloatUnderThresholdPredicate.of(1L, 0.0)) | ||
.rejects(TableWithBloat.of(Table.of("t2", 1L), 0L, 0.1)) | ||
.accepts(TableWithBloat.of(Table.of("t2", 100L), 1L, 0.0)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters