This is an automated email from the ASF dual-hosted git repository.

hanahmily pushed a commit to branch sidx/interface
in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git

commit 37a8640b7556e597938155afa64b5ccfa9d0fea3
Author: Gao Hongtao <hanahm...@gmail.com>
AuthorDate: Tue Aug 19 09:56:56 2025 +0700

    Add comprehensive interface usage examples for SIDX
    
    - Introduced `interfaces_examples.go` and `interfaces_examples_test.go` to 
demonstrate best practices and integration patterns for the Secondary Index 
File System (SIDX).
    - Included various examples covering basic write operations, advanced 
queries, error handling, performance optimizations, and contract compliance.
    - Enhanced documentation to provide clear guidance on using SIDX interfaces 
effectively, including error handling and performance considerations.
    - Updated `TODO.md` to reflect the completion of interface documentation 
and examples.
---
 banyand/internal/sidx/TODO.md                     |  22 +-
 banyand/internal/sidx/interfaces.go               |  14 +-
 banyand/internal/sidx/interfaces_examples.go      | 542 ++++++++++++++++++++++
 banyand/internal/sidx/interfaces_examples_test.go | 351 ++++++++++++++
 banyand/internal/sidx/options.go                  |   1 -
 banyand/internal/sidx/options_test.go             |   1 -
 6 files changed, 911 insertions(+), 20 deletions(-)

diff --git a/banyand/internal/sidx/TODO.md b/banyand/internal/sidx/TODO.md
index aa5dcd03..d9c7db83 100644
--- a/banyand/internal/sidx/TODO.md
+++ b/banyand/internal/sidx/TODO.md
@@ -5,7 +5,7 @@ This document tracks the implementation progress of the 
Secondary Index File Sys
 ## Implementation Progress Overview
 
 - [x] **Phase 1**: Core Data Structures (6 tasks) - 6/6 completed ✅
-- [x] **Phase 2**: Interface Definitions (5 tasks) - 4/5 completed ✅ **CORE 
INTERFACES READY**
+- [x] **Phase 2**: Interface Definitions (5 tasks) - 5/5 completed ✅ **CORE 
INTERFACES READY**
 - [ ] **Phase 3**: Mock Implementations (4 tasks) 🔥 **NEW - FOR EARLY TESTING**
 - [ ] **Phase 4**: Memory Management (4 tasks) 
 - [ ] **Phase 5**: Snapshot Management (4 tasks)
@@ -141,16 +141,16 @@ This document tracks the implementation progress of the 
Secondary Index File Sys
   - [x] Configuration validation works correctly
   - [x] Options can be merged and overridden
 
-### 2.5 Interface Documentation and Examples (`interfaces_examples.go`)
-- [ ] Create comprehensive interface usage examples
-- [ ] Document integration patterns with core storage
-- [ ] Add performance considerations and best practices
-- [ ] Create interface contract specifications
-- [ ] **Test Cases**:
-  - [ ] All examples compile and run correctly
-  - [ ] Documentation covers error handling patterns
-  - [ ] Integration examples are realistic
-  - [ ] Contract specifications are testable
+### 2.5 Interface Documentation and Examples (`interfaces_examples.go`) ✅
+- [x] Create comprehensive interface usage examples
+- [x] Document integration patterns with core storage
+- [x] Add performance considerations and best practices
+- [x] Create interface contract specifications
+- [x] **Test Cases**:
+  - [x] All examples compile and run correctly
+  - [x] Documentation covers error handling patterns
+  - [x] Integration examples are realistic
+  - [x] Contract specifications are testable
 
 ---
 
diff --git a/banyand/internal/sidx/interfaces.go 
b/banyand/internal/sidx/interfaces.go
index ddd33c4d..3c0e3830 100644
--- a/banyand/internal/sidx/interfaces.go
+++ b/banyand/internal/sidx/interfaces.go
@@ -196,14 +196,14 @@ func (qr *QueryResponse) Validate() error {
        keysLen := len(qr.Keys)
        dataLen := len(qr.Data)
        sidsLen := len(qr.SIDs)
-       
+
        if keysLen != dataLen {
                return fmt.Errorf("inconsistent array lengths: keys=%d, 
data=%d", keysLen, dataLen)
        }
        if keysLen != sidsLen {
                return fmt.Errorf("inconsistent array lengths: keys=%d, 
sids=%d", keysLen, sidsLen)
        }
-       
+
        // Validate Tags structure if present
        if len(qr.Tags) > 0 {
                if len(qr.Tags) != keysLen {
@@ -217,18 +217,18 @@ func (qr *QueryResponse) Validate() error {
                        }
                }
        }
-       
+
        return nil
 }
 
 // CopyFrom copies the QueryResponse from other to qr.
 func (qr *QueryResponse) CopyFrom(other *QueryResponse) {
        qr.Error = other.Error
-       
+
        // Copy parallel arrays
        qr.Keys = append(qr.Keys[:0], other.Keys...)
        qr.SIDs = append(qr.SIDs[:0], other.SIDs...)
-       
+
        // Deep copy data
        if cap(qr.Data) < len(other.Data) {
                qr.Data = make([][]byte, len(other.Data))
@@ -238,7 +238,7 @@ func (qr *QueryResponse) CopyFrom(other *QueryResponse) {
        for i, data := range other.Data {
                qr.Data[i] = append(qr.Data[i][:0], data...)
        }
-       
+
        // Deep copy tags
        if cap(qr.Tags) < len(other.Tags) {
                qr.Tags = make([][]Tag, len(other.Tags))
@@ -258,7 +258,7 @@ func (qr *QueryResponse) CopyFrom(other *QueryResponse) {
                        qr.Tags[i][j].indexed = tag.indexed
                }
        }
-       
+
        // Copy metadata
        qr.Metadata = other.Metadata
 }
diff --git a/banyand/internal/sidx/interfaces_examples.go 
b/banyand/internal/sidx/interfaces_examples.go
new file mode 100644
index 00000000..a194b912
--- /dev/null
+++ b/banyand/internal/sidx/interfaces_examples.go
@@ -0,0 +1,542 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Package sidx provides comprehensive interface usage examples and 
integration patterns
+// for the Secondary Index File System (SIDX). This file demonstrates proper 
usage
+// of SIDX interfaces, best practices, and integration with BanyanDB core 
storage.
+package sidx
+
+import (
+       "context"
+       "fmt"
+       "log"
+       "time"
+
+       "github.com/apache/skywalking-banyandb/api/common"
+       modelv1 
"github.com/apache/skywalking-banyandb/api/proto/banyandb/model/v1"
+       "github.com/apache/skywalking-banyandb/banyand/observability"
+       "github.com/apache/skywalking-banyandb/banyand/protector"
+       "github.com/apache/skywalking-banyandb/pkg/query/model"
+)
+
+// InterfaceUsageExamples demonstrates comprehensive usage patterns for SIDX 
interfaces.
+// These examples show real-world scenarios and proper error handling patterns.
+type InterfaceUsageExamples struct {
+       sidx SIDX
+}
+
+// NewInterfaceUsageExamples creates a new example instance with a mock SIDX 
implementation.
+// In production, this would be replaced with an actual SIDX instance.
+func NewInterfaceUsageExamples() *InterfaceUsageExamples {
+       // Configuration setup - demonstrates proper Options usage
+       _ = NewDefaultOptions().
+               WithPath("/data/sidx").
+               
WithMemory(protector.NewMemory(observability.NewBypassRegistry())).
+               WithMergePolicy(NewMergePolicy(8, 1.7, 1<<30))
+
+       // In production, this would create an actual SIDX instance:
+       // sidx, err := NewSIDX(ctx, opts)
+       // For examples, we use a mock implementation
+       sidx := &mockSIDX{}
+
+       return &InterfaceUsageExamples{
+               sidx: sidx,
+       }
+}
+
+// BasicWriteExample demonstrates basic batch writing with proper error 
handling.
+// This shows the fundamental write pattern used throughout BanyanDB.
+func (e *InterfaceUsageExamples) BasicWriteExample(ctx context.Context) error {
+       // Prepare batch write requests - demonstrates proper WriteRequest usage
+       writeReqs := []WriteRequest{
+               {
+                       SeriesID: common.SeriesID(1001),
+                       Key:      1640995200000, // Unix timestamp in 
milliseconds (opaque to SIDX)
+                       Data:     []byte(`{"service": "user-service", 
"endpoint": "/api/users"}`),
+                       Tags: []Tag{
+                               {name: "service", value: 
[]byte("user-service")},
+                               {name: "endpoint", value: []byte("/api/users")},
+                               {name: "status_code", value: int64ToBytes(200)},
+                       },
+               },
+               {
+                       SeriesID: common.SeriesID(1001),
+                       Key:      1640995260000,
+                       Data:     []byte(`{"service": "user-service", 
"endpoint": "/api/login"}`),
+                       Tags: []Tag{
+                               {name: "service", value: 
[]byte("user-service")},
+                               {name: "endpoint", value: []byte("/api/login")},
+                               {name: "status_code", value: int64ToBytes(401)},
+                       },
+               },
+       }
+
+       // Execute batch write with timeout context
+       writeCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
+       defer cancel()
+
+       if err := e.sidx.Write(writeCtx, writeReqs); err != nil {
+               return fmt.Errorf("batch write failed: %w", err)
+       }
+
+       log.Printf("Successfully wrote %d elements to SIDX", len(writeReqs))
+       return nil
+}
+
+// AdvancedQueryExample demonstrates complex querying with filtering and 
projection.
+// Shows integration with BanyanDB's index.Filter and query patterns.
+func (e *InterfaceUsageExamples) AdvancedQueryExample(ctx context.Context) 
error {
+       // Create query request with range and tag filtering
+       queryReq := QueryRequest{
+               Name: "trace-sidx",
+               Entities: [][]*modelv1.TagValue{
+                       {
+                               {Value: &modelv1.TagValue_Str{Str: 
&modelv1.Str{Value: "user-service"}}},
+                       },
+               },
+               Filter: nil, // In production, use actual index.Filter 
implementation
+               Order:  nil, // In production, use actual index.OrderBy 
implementation
+               TagProjection: []model.TagProjection{
+                       {Family: "service", Names: []string{"name"}},
+                       {Family: "endpoint", Names: []string{"path"}},
+                       {Family: "status", Names: []string{"code"}},
+               },
+               MaxElementSize: 1000,
+       }
+
+       // Execute query with timeout context
+       queryCtx, cancel := context.WithTimeout(ctx, 60*time.Second)
+       defer cancel()
+
+       result, err := e.sidx.Query(queryCtx, queryReq)
+       if err != nil {
+               return fmt.Errorf("query failed: %w", err)
+       }
+       defer result.Release() // Critical: always release resources
+
+       // Iterate through results using Pull pattern
+       totalResults := 0
+       for {
+               response := result.Pull()
+               if response == nil {
+                       break // No more results
+               }
+
+               // Check for execution errors during iteration
+               if response.Error != nil {
+                       return fmt.Errorf("query execution error: %w", 
response.Error)
+               }
+
+               // Process results batch
+               for i := 0; i < response.Len(); i++ {
+                       log.Printf("Result %d: Key=%d, SeriesID=%d, Data=%s",
+                               totalResults+i+1,
+                               response.Keys[i],
+                               response.SIDs[i],
+                               string(response.Data[i]))
+
+                       // Process tags if needed
+                       if i < len(response.Tags) {
+                               for _, tag := range response.Tags[i] {
+                                       log.Printf("  Tag: %s = %s", tag.name, 
string(tag.value))
+                               }
+                       }
+               }
+
+               totalResults += response.Len()
+               log.Printf("Processed batch: %d results, metadata: %+v",
+                       response.Len(), response.Metadata)
+       }
+
+       log.Printf("Query completed: %d total results", totalResults)
+       return nil
+}
+
+// FlushAndMergeExample demonstrates manual control over persistence and 
compaction.
+// Shows when and how to trigger flush and merge operations for optimal 
performance.
+func (e *InterfaceUsageExamples) FlushAndMergeExample(ctx context.Context) 
error {
+       // Check stats before operations
+       stats, err := e.sidx.Stats(ctx)
+       if err != nil {
+               return fmt.Errorf("failed to get stats: %w", err)
+       }
+
+       log.Printf("Before operations - Memory: %d bytes, Disk: %d bytes, 
Parts: %d",
+               stats.MemoryUsageBytes, stats.DiskUsageBytes, stats.PartCount)
+
+       // Trigger flush to persist memory parts
+       if err := e.sidx.Flush(); err != nil {
+               return fmt.Errorf("flush operation failed: %w", err)
+       }
+       log.Println("Flush completed successfully")
+
+       // Trigger merge to compact parts
+       if err := e.sidx.Merge(); err != nil {
+               return fmt.Errorf("merge operation failed: %w", err)
+       }
+       log.Println("Merge completed successfully")
+
+       // Check stats after operations
+       statsAfter, err := e.sidx.Stats(ctx)
+       if err != nil {
+               return fmt.Errorf("failed to get stats after operations: %w", 
err)
+       }
+
+       log.Printf("After operations - Memory: %d bytes, Disk: %d bytes, Parts: 
%d",
+               statsAfter.MemoryUsageBytes, statsAfter.DiskUsageBytes, 
statsAfter.PartCount)
+
+       return nil
+}
+
+// ErrorHandlingExample demonstrates comprehensive error handling patterns.
+// Shows how to handle different types of errors and recovery strategies.
+func (e *InterfaceUsageExamples) ErrorHandlingExample(ctx context.Context) {
+       // Example 1: Write error handling
+       writeReqs := []WriteRequest{
+               {
+                       SeriesID: common.SeriesID(0), // Invalid SeriesID
+                       Key:      1640995200000,
+                       Data:     []byte("test data"),
+                       Tags:     []Tag{{name: "test", value: []byte("value")}},
+               },
+       }
+
+       if err := e.sidx.Write(ctx, writeReqs); err != nil {
+               log.Printf("Write error (expected): %v", err)
+               // In production: implement retry logic, circuit breaker, etc.
+       }
+
+       // Example 2: Query error handling
+       invalidQuery := QueryRequest{
+               Name:           "", // Invalid name
+               MaxElementSize: -1, // Invalid size
+       }
+
+       result, err := e.sidx.Query(ctx, invalidQuery)
+       if err != nil {
+               log.Printf("Query setup error (expected): %v", err)
+               // Handle setup errors - usually validation failures
+               return
+       }
+
+       if result != nil {
+               defer result.Release()
+
+               // Handle execution errors during iteration
+               for {
+                       response := result.Pull()
+                       if response == nil {
+                               break
+                       }
+
+                       if response.Error != nil {
+                               log.Printf("Query execution error: %v", 
response.Error)
+                               // Handle execution errors - partial results 
may be available
+                               break
+                       }
+               }
+       }
+}
+
+// PerformanceOptimizationExample demonstrates best practices for optimal 
performance.
+// Shows batching, sorting, and resource management strategies.
+func (e *InterfaceUsageExamples) PerformanceOptimizationExample(ctx 
context.Context) error {
+       // Best Practice 1: Batch writes for optimal throughput
+       const batchSize = 1000
+       writeReqs := make([]WriteRequest, 0, batchSize)
+
+       // Best Practice 2: Pre-sort elements by SeriesID then Key
+       // This optimizes block construction and reduces fragmentation
+       for seriesID := 1; seriesID <= 10; seriesID++ {
+               for i := 0; i < 100; i++ {
+                       writeReqs = append(writeReqs, WriteRequest{
+                               SeriesID: common.SeriesID(seriesID),
+                               Key:      int64(1640995200000 + i*1000), // 
Sequential keys
+                               Data:     
[]byte(fmt.Sprintf(`{"series":%d,"seq":%d}`, seriesID, i)),
+                               Tags: []Tag{
+                                       {name: "series_id", value: 
int64ToBytes(int64(seriesID))},
+                                       {name: "sequence", value: 
int64ToBytes(int64(i))},
+                               },
+                       })
+               }
+       }
+
+       // Execute optimized batch write
+       start := time.Now()
+       if err := e.sidx.Write(ctx, writeReqs); err != nil {
+               return fmt.Errorf("optimized batch write failed: %w", err)
+       }
+       writeDuration := time.Since(start)
+
+       log.Printf("Optimized batch write: %d elements in %v (%.2f elem/sec)",
+               len(writeReqs), writeDuration, 
float64(len(writeReqs))/writeDuration.Seconds())
+
+       // Best Practice 3: Use appropriate query limits
+       queryReq := QueryRequest{
+               Name:           "performance-test",
+               MaxElementSize: 100, // Reasonable batch size
+               TagProjection: []model.TagProjection{
+                       {Family: "series", Names: []string{"id"}}, // Only 
project needed tags
+               },
+       }
+
+       result, err := e.sidx.Query(ctx, queryReq)
+       if err != nil {
+               return fmt.Errorf("performance query failed: %w", err)
+       }
+       defer result.Release()
+
+       // Process results efficiently
+       queryStart := time.Now()
+       resultCount := 0
+       for {
+               response := result.Pull()
+               if response == nil {
+                       break
+               }
+               if response.Error != nil {
+                       return fmt.Errorf("query execution error: %w", 
response.Error)
+               }
+               resultCount += response.Len()
+       }
+       queryDuration := time.Since(queryStart)
+
+       log.Printf("Optimized query: %d results in %v (%.2f results/sec)",
+               resultCount, queryDuration, 
float64(resultCount)/queryDuration.Seconds())
+
+       return nil
+}
+
+// IntegrationPatternExample demonstrates integration with BanyanDB core 
storage.
+// Shows how SIDX interfaces integrate with existing BanyanDB patterns and 
workflows.
+func (e *InterfaceUsageExamples) IntegrationPatternExample(ctx 
context.Context) error {
+       // Integration Pattern 1: Following BanyanDB's context-aware operations
+       // Use context for timeout control and cancellation
+       operationCtx, cancel := context.WithTimeout(ctx, 5*time.Minute)
+       defer cancel()
+
+       // Integration Pattern 2: Statistics monitoring (like other BanyanDB 
components)
+       stats, err := e.sidx.Stats(operationCtx)
+       if err != nil {
+               return fmt.Errorf("stats integration failed: %w", err)
+       }
+
+       // Integration Pattern 3: Metric collection for observability
+       log.Printf("SIDX Metrics - Elements: %d, Parts: %d, Queries: %d",
+               stats.ElementCount, stats.PartCount, stats.QueryCount)
+
+       // Integration Pattern 4: Resource management following BanyanDB 
patterns
+       // Proper cleanup and resource release
+       defer func() {
+               if closeErr := e.sidx.Close(); closeErr != nil {
+                       log.Printf("SIDX close error: %v", closeErr)
+               }
+       }()
+
+       // Integration Pattern 5: Error handling consistent with BanyanDB
+       // Use structured errors and proper error wrapping
+       if stats.MemoryUsageBytes > 1<<30 { // 1GB threshold
+               log.Println("High memory usage detected, triggering 
maintenance")
+
+               if err := e.sidx.Flush(); err != nil {
+                       // Don't fail the operation, but log the issue
+                       log.Printf("Maintenance flush failed: %v", err)
+               }
+
+               if err := e.sidx.Merge(); err != nil {
+                       log.Printf("Maintenance merge failed: %v", err)
+               }
+       }
+
+       return nil
+}
+
+// int64ToBytes converts an int64 to bytes for tag values.
+// This utility function demonstrates proper tag value encoding.
+func int64ToBytes(val int64) []byte {
+       result := make([]byte, 8)
+       for i := 0; i < 8; i++ {
+               result[7-i] = byte(val >> (8 * i))
+       }
+       return result
+}
+
+// mockSIDX provides a simple mock implementation for example purposes.
+// In production, this would be replaced with the actual SIDX implementation.
+type mockSIDX struct{}
+
+func (m *mockSIDX) Write(ctx context.Context, reqs []WriteRequest) error {
+       if len(reqs) == 0 {
+               return fmt.Errorf("empty write request")
+       }
+       for i, req := range reqs {
+               if req.SeriesID == 0 {
+                       return fmt.Errorf("invalid SeriesID at index %d", i)
+               }
+       }
+       return nil
+}
+
+func (m *mockSIDX) Query(ctx context.Context, req QueryRequest) (QueryResult, 
error) {
+       if req.Name == "" {
+               return nil, fmt.Errorf("query name cannot be empty")
+       }
+       if req.MaxElementSize < 0 {
+               return nil, fmt.Errorf("invalid MaxElementSize: %d", 
req.MaxElementSize)
+       }
+       return &mockQueryResult{}, nil
+}
+
+func (m *mockSIDX) Stats(ctx context.Context) (Stats, error) {
+       return Stats{
+               MemoryUsageBytes: 1024 * 1024 * 100, // 100MB
+               DiskUsageBytes:   1024 * 1024 * 500, // 500MB
+               ElementCount:     10000,
+               PartCount:        5,
+               QueryCount:       1000,
+       }, nil
+}
+
+func (m *mockSIDX) Close() error {
+       return nil
+}
+
+func (m *mockSIDX) Flush() error {
+       return nil
+}
+
+func (m *mockSIDX) Merge() error {
+       return nil
+}
+
+// mockQueryResult provides a simple mock query result for examples.
+type mockQueryResult struct {
+       pulled bool
+}
+
+func (m *mockQueryResult) Pull() *QueryResponse {
+       if m.pulled {
+               return nil // No more results
+       }
+       m.pulled = true
+
+       return &QueryResponse{
+               Keys: []int64{1640995200000, 1640995260000},
+               Data: [][]byte{
+                       []byte(`{"service": "user-service", "endpoint": 
"/api/users"}`),
+                       []byte(`{"service": "user-service", "endpoint": 
"/api/login"}`),
+               },
+               Tags: [][]Tag{
+                       {{name: "service", value: []byte("user-service")}},
+                       {{name: "service", value: []byte("user-service")}},
+               },
+               SIDs: []common.SeriesID{1001, 1001},
+               Metadata: ResponseMetadata{
+                       ExecutionTimeMs:  100,
+                       ElementsScanned:  1000,
+                       ElementsFiltered: 998,
+               },
+       }
+}
+
+func (m *mockQueryResult) Release() {
+       // Mock implementation - no resources to release
+}
+
+// Note: In production code, you would use actual index.Filter and 
index.OrderBy implementations
+// from the BanyanDB index package. These examples use nil values for 
simplicity,
+// but real applications should create proper filter and ordering 
specifications.
+
+// Contract Specifications and Testing Guidelines
+//
+// The following section provides contract specifications for each interface
+// to guide testing and implementation verification.
+
+// SIDXContract defines the behavioral contract for SIDX implementations.
+// All SIDX implementations must satisfy these contracts.
+type SIDXContract struct {
+       // Write Contract:
+       // - MUST accept batch writes with pre-sorted elements
+       // - MUST validate WriteRequest fields (non-zero SeriesID, valid tags)
+       // - MUST handle context cancellation gracefully
+       // - MUST return detailed error information for validation failures
+       // - SHOULD optimize for sequential key writes within series
+
+       // Query Contract:
+       // - MUST return QueryResult that implements Pull/Release pattern
+       // - MUST handle context timeout and cancellation
+       // - MUST validate QueryRequest parameters before execution
+       // - MUST provide error information in QueryResponse.Error for 
execution failures
+       // - MUST maintain result ordering based on QueryRequest.Order
+       // - MUST respect MaxElementSize limits
+
+       // Stats Contract:
+       // - MUST return current system metrics
+       // - MUST handle context timeout
+       // - SHOULD provide accurate memory and disk usage information
+       // - SHOULD update counters atomically
+
+       // Close Contract:
+       // - MUST ensure all data is persisted before closing
+       // - MUST release all resources
+       // - MUST be idempotent (safe to call multiple times)
+       // - SHOULD complete within reasonable time (suggest timeout)
+
+       // Flush Contract:
+       // - MUST persist memory parts to disk
+       // - MUST be synchronous operation
+       // - MUST coordinate with snapshot management
+       // - SHOULD optimize part selection for efficiency
+
+       // Merge Contract:
+       // - MUST maintain key ordering during merge
+       // - MUST be synchronous operation
+       // - MUST coordinate with snapshot management
+       // - SHOULD optimize part selection to minimize write amplification
+}
+
+// Performance Considerations and Best Practices
+//
+// 1. **Write Performance**:
+//    - Always use batch writes instead of individual writes
+//    - Pre-sort elements by SeriesID then Key for optimal block construction
+//    - Use sequential keys within series when possible
+//    - Monitor memory usage and trigger flushes proactively
+//
+// 2. **Query Performance**:
+//    - Use appropriate MaxElementSize to balance memory and latency
+//    - Project only needed tags to reduce I/O
+//    - Use key range filters to minimize part scanning
+//    - Release QueryResult promptly to free resources
+//
+// 3. **Resource Management**:
+//    - Monitor Stats regularly for system health
+//    - Trigger Flush operations before memory limits
+//    - Use Merge operations to control part count and storage efficiency
+//    - Always call Close() for clean shutdown
+//
+// 4. **Error Handling**:
+//    - Distinguish between setup errors (Query return) and execution errors 
(QueryResponse.Error)
+//    - Implement retry logic for transient failures
+//    - Use context timeout for all operations
+//    - Log detailed error information for debugging
+//
+// 5. **Integration Patterns**:
+//    - Follow BanyanDB context patterns for timeout and cancellation
+//    - Use structured logging for observability
+//    - Implement proper metrics collection
+//    - Follow BanyanDB error handling conventions
diff --git a/banyand/internal/sidx/interfaces_examples_test.go 
b/banyand/internal/sidx/interfaces_examples_test.go
new file mode 100644
index 00000000..e48cc18b
--- /dev/null
+++ b/banyand/internal/sidx/interfaces_examples_test.go
@@ -0,0 +1,351 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package sidx
+
+import (
+       "context"
+       "testing"
+       "time"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestInterfaceUsageExamples(t *testing.T) {
+       examples := NewInterfaceUsageExamples()
+       require.NotNil(t, examples)
+       require.NotNil(t, examples.sidx)
+
+       ctx := context.Background()
+
+       t.Run("BasicWriteExample", func(t *testing.T) {
+               err := examples.BasicWriteExample(ctx)
+               assert.NoError(t, err)
+       })
+
+       t.Run("AdvancedQueryExample", func(t *testing.T) {
+               err := examples.AdvancedQueryExample(ctx)
+               assert.NoError(t, err)
+       })
+
+       t.Run("FlushAndMergeExample", func(t *testing.T) {
+               err := examples.FlushAndMergeExample(ctx)
+               assert.NoError(t, err)
+       })
+
+       t.Run("ErrorHandlingExample", func(t *testing.T) {
+               // This example doesn't return errors, just demonstrates error 
handling
+               examples.ErrorHandlingExample(ctx)
+       })
+
+       t.Run("PerformanceOptimizationExample", func(t *testing.T) {
+               err := examples.PerformanceOptimizationExample(ctx)
+               assert.NoError(t, err)
+       })
+
+       t.Run("IntegrationPatternExample", func(t *testing.T) {
+               err := examples.IntegrationPatternExample(ctx)
+               assert.NoError(t, err)
+       })
+}
+
+func TestMockSIDXImplementation(t *testing.T) {
+       sidx := &mockSIDX{}
+       ctx := context.Background()
+
+       t.Run("Write validates input", func(t *testing.T) {
+               // Test empty write request
+               err := sidx.Write(ctx, []WriteRequest{})
+               assert.Error(t, err)
+               assert.Contains(t, err.Error(), "empty write request")
+
+               // Test invalid SeriesID
+               err = sidx.Write(ctx, []WriteRequest{
+                       {SeriesID: 0, Key: 123, Data: []byte("test")},
+               })
+               assert.Error(t, err)
+               assert.Contains(t, err.Error(), "invalid SeriesID")
+
+               // Test valid write request
+               err = sidx.Write(ctx, []WriteRequest{
+                       {SeriesID: 1001, Key: 123, Data: []byte("test")},
+               })
+               assert.NoError(t, err)
+       })
+
+       t.Run("Query validates input", func(t *testing.T) {
+               // Test empty query name
+               result, err := sidx.Query(ctx, QueryRequest{Name: ""})
+               assert.Error(t, err)
+               assert.Nil(t, result)
+               assert.Contains(t, err.Error(), "query name cannot be empty")
+
+               // Test invalid MaxElementSize
+               result, err = sidx.Query(ctx, QueryRequest{
+                       Name:           "test",
+                       MaxElementSize: -1,
+               })
+               assert.Error(t, err)
+               assert.Nil(t, result)
+               assert.Contains(t, err.Error(), "invalid MaxElementSize")
+
+               // Test valid query
+               result, err = sidx.Query(ctx, QueryRequest{
+                       Name:           "test",
+                       MaxElementSize: 100,
+               })
+               assert.NoError(t, err)
+               assert.NotNil(t, result)
+               result.Release()
+       })
+
+       t.Run("Stats returns valid data", func(t *testing.T) {
+               stats, err := sidx.Stats(ctx)
+               assert.NoError(t, err)
+               assert.Greater(t, stats.MemoryUsageBytes, int64(0))
+               assert.Greater(t, stats.DiskUsageBytes, int64(0))
+               assert.Greater(t, stats.ElementCount, int64(0))
+               assert.Greater(t, stats.PartCount, int64(0))
+               assert.Greater(t, stats.QueryCount, int64(0))
+       })
+
+       t.Run("Flush and Merge succeed", func(t *testing.T) {
+               err := sidx.Flush()
+               assert.NoError(t, err)
+
+               err = sidx.Merge()
+               assert.NoError(t, err)
+       })
+
+       t.Run("Close succeeds", func(t *testing.T) {
+               err := sidx.Close()
+               assert.NoError(t, err)
+       })
+}
+
+func TestMockQueryResult(t *testing.T) {
+       result := &mockQueryResult{}
+
+       t.Run("Pull returns data once", func(t *testing.T) {
+               // First pull should return data
+               response := result.Pull()
+               assert.NotNil(t, response)
+               assert.NoError(t, response.Error)
+               assert.Equal(t, 2, response.Len())
+               assert.Len(t, response.Keys, 2)
+               assert.Len(t, response.Data, 2)
+               assert.Len(t, response.Tags, 2)
+               assert.Len(t, response.SIDs, 2)
+
+               // Validate response metadata
+               assert.Greater(t, response.Metadata.ExecutionTimeMs, int64(0))
+               assert.Greater(t, response.Metadata.ElementsScanned, int64(0))
+               assert.Greater(t, response.Metadata.ElementsFiltered, int64(0))
+
+               // Second pull should return nil (no more data)
+               response = result.Pull()
+               assert.Nil(t, response)
+       })
+
+       t.Run("Release doesn't panic", func(t *testing.T) {
+               // Should not panic
+               result.Release()
+       })
+}
+
+func TestInt64ToBytes(t *testing.T) {
+       testCases := []struct {
+               name     string
+               input    int64
+               expected []byte
+       }{
+               {
+                       name:     "zero value",
+                       input:    0,
+                       expected: []byte{0, 0, 0, 0, 0, 0, 0, 0},
+               },
+               {
+                       name:     "positive value",
+                       input:    1640995200000,
+                       expected: []byte{0, 0, 1, 0x7e, 0x12, 0xef, 0x9c, 0x0},
+               },
+               {
+                       name:     "negative value",
+                       input:    -1,
+                       expected: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff},
+               },
+               {
+                       name:     "max int64",
+                       input:    9223372036854775807, // math.MaxInt64
+                       expected: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff},
+               },
+       }
+
+       for _, tc := range testCases {
+               t.Run(tc.name, func(t *testing.T) {
+                       result := int64ToBytes(tc.input)
+                       assert.Equal(t, tc.expected, result)
+                       assert.Len(t, result, 8) // Should always be 8 bytes
+               })
+       }
+}
+
+func TestExamplesWithTimeout(t *testing.T) {
+       examples := NewInterfaceUsageExamples()
+
+       // Test with very short timeout to ensure context handling works
+       ctx, cancel := context.WithTimeout(context.Background(), 
1*time.Nanosecond)
+       defer cancel()
+
+       // Allow some time for context to expire
+       time.Sleep(1 * time.Millisecond)
+
+       t.Run("BasicWriteExample with timeout", func(t *testing.T) {
+               // This should handle context timeout gracefully
+               // The mock implementation doesn't actually check context, but 
real implementations should
+               err := examples.BasicWriteExample(ctx)
+               // In a real implementation, this might return a context 
deadline exceeded error
+               // For our mock, it should still succeed
+               assert.NoError(t, err)
+       })
+}
+
+func TestContractCompliance(t *testing.T) {
+       // This test verifies that our mock implementations follow the 
documented contracts
+       sidx := &mockSIDX{}
+       ctx := context.Background()
+
+       t.Run("Write contract compliance", func(t *testing.T) {
+               // Contract: MUST validate WriteRequest fields
+               err := sidx.Write(ctx, []WriteRequest{{SeriesID: 0}})
+               assert.Error(t, err, "Should validate non-zero SeriesID")
+
+               // Contract: MUST accept batch writes
+               err = sidx.Write(ctx, []WriteRequest{
+                       {SeriesID: 1, Key: 1, Data: []byte("test1")},
+                       {SeriesID: 1, Key: 2, Data: []byte("test2")},
+               })
+               assert.NoError(t, err, "Should accept valid batch writes")
+       })
+
+       t.Run("Query contract compliance", func(t *testing.T) {
+               // Contract: MUST validate QueryRequest parameters
+               _, err := sidx.Query(ctx, QueryRequest{Name: ""})
+               assert.Error(t, err, "Should validate query name")
+
+               // Contract: MUST return QueryResult with Pull/Release pattern
+               result, err := sidx.Query(ctx, QueryRequest{Name: "test"})
+               assert.NoError(t, err)
+               assert.NotNil(t, result, "Should return QueryResult")
+
+               // Contract: Pull/Release pattern should work
+               response := result.Pull()
+               assert.NotNil(t, response, "First pull should return data")
+
+               response = result.Pull()
+               assert.Nil(t, response, "Second pull should return nil")
+
+               // Contract: Release should be safe to call
+               result.Release()
+       })
+
+       t.Run("Stats contract compliance", func(t *testing.T) {
+               // Contract: MUST return current system metrics
+               stats, err := sidx.Stats(ctx)
+               assert.NoError(t, err)
+
+               // All metrics should be non-negative
+               assert.GreaterOrEqual(t, stats.MemoryUsageBytes, int64(0))
+               assert.GreaterOrEqual(t, stats.DiskUsageBytes, int64(0))
+               assert.GreaterOrEqual(t, stats.ElementCount, int64(0))
+               assert.GreaterOrEqual(t, stats.PartCount, int64(0))
+               assert.GreaterOrEqual(t, stats.QueryCount, int64(0))
+       })
+
+       t.Run("Close contract compliance", func(t *testing.T) {
+               // Contract: MUST be idempotent
+               err := sidx.Close()
+               assert.NoError(t, err)
+
+               err = sidx.Close()
+               assert.NoError(t, err, "Close should be idempotent")
+       })
+
+       t.Run("Flush contract compliance", func(t *testing.T) {
+               // Contract: MUST be synchronous
+               err := sidx.Flush()
+               assert.NoError(t, err, "Flush should be synchronous")
+       })
+
+       t.Run("Merge contract compliance", func(t *testing.T) {
+               // Contract: MUST be synchronous
+               err := sidx.Merge()
+               assert.NoError(t, err, "Merge should be synchronous")
+       })
+}
+
+func BenchmarkInt64ToBytes(b *testing.B) {
+       values := []int64{0, 1, -1, 1640995200000, 9223372036854775807}
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               for _, val := range values {
+                       _ = int64ToBytes(val)
+               }
+       }
+}
+
+func BenchmarkMockWriteOperations(b *testing.B) {
+       sidx := &mockSIDX{}
+       ctx := context.Background()
+
+       reqs := []WriteRequest{
+               {SeriesID: 1001, Key: 1640995200000, Data: []byte("test data")},
+               {SeriesID: 1002, Key: 1640995260000, Data: []byte("more test 
data")},
+       }
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               _ = sidx.Write(ctx, reqs)
+       }
+}
+
+func BenchmarkMockQueryOperations(b *testing.B) {
+       sidx := &mockSIDX{}
+       ctx := context.Background()
+
+       req := QueryRequest{
+               Name:           "benchmark",
+               MaxElementSize: 100,
+       }
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               result, err := sidx.Query(ctx, req)
+               if err != nil {
+                       b.Fatal(err)
+               }
+               for {
+                       response := result.Pull()
+                       if response == nil {
+                               break
+                       }
+               }
+               result.Release()
+       }
+}
diff --git a/banyand/internal/sidx/options.go b/banyand/internal/sidx/options.go
index c1daf36d..91dbb70a 100644
--- a/banyand/internal/sidx/options.go
+++ b/banyand/internal/sidx/options.go
@@ -143,4 +143,3 @@ func (o *Options) WithMergePolicy(policy *MergePolicy) 
*Options {
        opts.MergePolicy = policy
        return &opts
 }
-
diff --git a/banyand/internal/sidx/options_test.go 
b/banyand/internal/sidx/options_test.go
index 1967096f..c691a219 100644
--- a/banyand/internal/sidx/options_test.go
+++ b/banyand/internal/sidx/options_test.go
@@ -268,4 +268,3 @@ func TestOptionsEdgeCases(t *testing.T) {
                assert.NoError(t, policy.Validate())
        })
 }
-


Reply via email to