Skip to content

⚡️ Speed up method Filter.geoWithinRegionByIndex by 11%#103

Open
codeflash-ai[bot] wants to merge 1 commit intofix/add-mockito-test-dependencyfrom
codeflash/optimize-Filter.geoWithinRegionByIndex-mmbtvlcn
Open

⚡️ Speed up method Filter.geoWithinRegionByIndex by 11%#103
codeflash-ai[bot] wants to merge 1 commit intofix/add-mockito-test-dependencyfrom
codeflash/optimize-Filter.geoWithinRegionByIndex-mmbtvlcn

Conversation

@codeflash-ai
Copy link
Copy Markdown

@codeflash-ai codeflash-ai bot commented Mar 4, 2026

📄 11% (0.11x) speedup for Filter.geoWithinRegionByIndex in client/src/com/aerospike/client/query/Filter.java

⏱️ Runtime : 11.6 microseconds 10.4 microseconds (best of 169 runs)

📝 Explanation and details

This change reduces runtime by 11% (11.6 μs → 10.4 μs) by calling Value.get(region) once and reusing that Value for both begin and end instead of creating two Value objects. Reusing the single Value eliminates one method call and one object allocation per Filter construction, cutting per-invocation CPU and allocation overhead on the hot path. Trade-off: begin and end now share the same Value instance (i.e., object identity is aliased), which is appropriate for the effectively immutable Value type and produced no measurable test regressions while slightly lowering memory churn.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 10 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 0.0%
🌀 Click to see Generated Regression Tests
package com.aerospike.client.query;

import org.junit.Test;
import org.junit.Before;
import static org.junit.Assert.*;

import java.lang.reflect.Field;

import com.aerospike.client.Value;
import com.aerospike.client.command.ParticleType;
// Performance comparison:
// FilterTest.testEmptyIndexName_AllowsEmptyIndexName#3: 0.001ms -> 0.001ms (15.2% faster)
// FilterTest.testLargeRegion_HandlesLargeInput#6: 0.001ms -> 0.001ms (-15.4% faster)
// FilterTest.testNullRegion_ThrowsNullPointerException#5: 0.001ms -> 0.001ms (-12.2% faster)
// FilterTest.testNullIndexName_AllowsNullIndexName#4: 0.001ms -> 0.001ms (20.0% faster)
// FilterTest.testEmptyRegion_CreatesFilterWithEmptyValues#2: 0.001ms -> 0.001ms (15.0% faster)
// FilterTest.testTypicalInput_CreatesFilterWithExpectedFields#1: 0.001ms -> 0.001ms (6.1% faster)
// FilterTest.testGeoWithinRegionByIndex_LargeRegion_HandlesLargeInput#6: 0.001ms -> 0.001ms (-10.6% faster)
// FilterTest.testGeoWithinRegionByIndex_NullRegion_HandlesNullOrThrows#7: 0.005ms -> 0.005ms (12.1% faster)
// FilterTest.testGeoWithinRegionByIndex_EmptyRegion_ReturnsNonNullBeginAndEnd#4: 0.001ms -> 0.001ms (19.9% faster)
// FilterTest.testGeoWithinRegionByIndex_NullIndexName_AllowsNullIndexName#5: 0.001ms -> 0.001ms (31.2% faster)

/**
 * Unit tests for com.aerospike.client.query.Filter.geoWithinRegionByIndex
 *
 * These tests validate that the created Filter instance contains the expected
 * internal state given various inputs. Reflection is used to access private
 * fields on Filter because the class does not expose getters for these fields.
 */
public class FilterTest {
    private static final String SAMPLE_REGION = "{\"type\":\"Polygon\",\"coordinates\":[[[0,0],[0,1],[1,1],[0,0]]]}";

    // Helper to read private fields from Filter via reflection.
    private Object getPrivateField(Object instance, String fieldName) throws Exception {
        Field f = Filter.class.getDeclaredField(fieldName);
        f.setAccessible(true);
        return f.get(instance);
    }

    @Before
    public void setUp() {
        // No persistent instance required before tests; each test will create its own Filter.
    }

    @Test
    public void testTypicalInput_CreatesFilterWithExpectedFields() throws Exception {
        Filter f = Filter.geoWithinRegionByIndex("myIndex", IndexCollectionType.LIST, SAMPLE_REGION);

        // indexName should match provided
        assertEquals("myIndex", getPrivateField(f, "indexName"));

        // name should be null when created by indexName constructor
        assertEquals(null, getPrivateField(f, "name"));

        // collection type should match
        assertEquals(IndexCollectionType.LIST, getPrivateField(f, "colType"));

        // value type should be GEOJSON
        assertEquals(ParticleType.GEOJSON, getPrivateField(f, "valType"));

        // packed context and packed expression should be null for this constructor
        assertEquals(null, getPrivateField(f, "packedCtx"));
        assertEquals(null, getPrivateField(f, "packedExp"));

        // begin and end should be Value instances wrapping the provided region string
        Object begin = getPrivateField(f, "begin");
        Object end = getPrivateField(f, "end");
        assertNotNull(begin);
        assertNotNull(end);
        assertTrue(begin instanceof Value);
        assertTrue(end instanceof Value);

        // Verify that the underlying value is the same region string
        assertEquals(SAMPLE_REGION, ((Value) begin).getObject());
        assertEquals(SAMPLE_REGION, ((Value) end).getObject());
    }

    @Test
    public void testEmptyRegion_CreatesFilterWithEmptyValues() throws Exception {
        String emptyRegion = "";
        Filter f = Filter.geoWithinRegionByIndex("idxEmpty", IndexCollectionType.LIST, emptyRegion);

        // begin and end should wrap the empty string
        Value begin = (Value) getPrivateField(f, "begin");
        Value end = (Value) getPrivateField(f, "end");
        assertNotNull(begin);
        assertNotNull(end);
        assertEquals("", begin.getObject());
        assertEquals("", end.getObject());
    }

    @Test
    public void testEmptyIndexName_AllowsEmptyIndexName() throws Exception {
        String region = SAMPLE_REGION;
        Filter f = Filter.geoWithinRegionByIndex("", IndexCollectionType.LIST, region);

        // indexName should reflect the empty string provided
        assertEquals("", getPrivateField(f, "indexName"));

        // begin should be set to the region
        Value begin = (Value) getPrivateField(f, "begin");
        assertEquals(region, begin.getObject());
    }

    @Test
    public void testNullIndexName_AllowsNullIndexName() throws Exception {
        // Passing null as indexName should result in a Filter instance with indexName == null.
        // The constructor does not explicitly prohibit null indexName.
        Filter f = Filter.geoWithinRegionByIndex(null, IndexCollectionType.LIST, SAMPLE_REGION);
        assertEquals(null, getPrivateField(f, "indexName"));

        // begin should still be set
        Value begin = (Value) getPrivateField(f, "begin");
        assertEquals(SAMPLE_REGION, begin.getObject());
    }

    @Test(expected = NullPointerException.class)
    public void testNullRegion_ThrowsNullPointerException() {
        // Depending on Value.get implementation, passing null region may throw.
        // This test documents an expected NullPointerException when region is null.
        // If the implementation changes to allow null, this test should be updated.
        Filter.geoWithinRegionByIndex("idx", IndexCollectionType.LIST, null);
    }

    @Test
    public void testLargeRegion_HandlesLargeInput() throws Exception {
        // Construct a large GeoJSON-like string (repeated pattern)
        StringBuilder sb = new StringBuilder();
        sb.append("{\"type\":\"MultiPolygon\",\"coordinates\":[");
        for (int i = 0; i < 5000; i++) {
            sb.append("[[[");
            sb.append(i).append(",").append(i);
            sb.append("]]]");
            if (i < 4999) {
                sb.append(",");
            }
        }
        sb.append("]}");
        String largeRegion = sb.toString();

        Filter f = Filter.geoWithinRegionByIndex("largeIdx", IndexCollectionType.LIST, largeRegion);

        // Basic sanity checks: index name and begin/end values are set and equal to large region
        assertEquals("largeIdx", getPrivateField(f, "indexName"));
        Value begin = (Value) getPrivateField(f, "begin");
        Value end = (Value) getPrivateField(f, "end");
        assertEquals(largeRegion, begin.getObject());
        assertEquals(largeRegion, end.getObject());
    }
}

To edit these changes git checkout codeflash/optimize-Filter.geoWithinRegionByIndex-mmbtvlcn and push.

Codeflash Static Badge

This change reduces runtime by 11% (11.6 μs → 10.4 μs) by calling Value.get(region) once and reusing that Value for both begin and end instead of creating two Value objects. Reusing the single Value eliminates one method call and one object allocation per Filter construction, cutting per-invocation CPU and allocation overhead on the hot path. Trade-off: begin and end now share the same Value instance (i.e., object identity is aliased), which is appropriate for the effectively immutable Value type and produced no measurable test regressions while slightly lowering memory churn.
@codeflash-ai codeflash-ai bot requested a review from misrasaurabh1 March 4, 2026 09:22
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Mar 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants