fix in-memory variables

This commit is contained in:
chrislu committed 2025-09-12 23:50:07 -07:00
1 parent 78382b380e
commit e6f7e7efb5
8 files changed
+85 -285

No files matched your search

+1 -4
View File
@@ -93,10 +93,7 @@ func (h *Handler) handleFetch(correlationID uint32, apiVersion uint16, requestBo
} }
// If topic does not exist, patch error to UNKNOWN_TOPIC_OR_PARTITION // If topic does not exist, patch error to UNKNOWN_TOPIC_OR_PARTITION
h.topicsMu.RLock() if !h.seaweedMQHandler.TopicExists(topic.Name) {
_, topicExists := h.topics[topic.Name]
h.topicsMu.RUnlock()
if !topicExists {
response[errorPos] = 0 response[errorPos] = 0
response[errorPos+1] = 3 // UNKNOWN_TOPIC_OR_PARTITION response[errorPos+1] = 3 // UNKNOWN_TOPIC_OR_PARTITION
} }
+4 -10
View File
@@ -12,11 +12,8 @@ func TestHandler_handleFetch(t *testing.T) {
// Create a topic and add some records // Create a topic and add some records
topicName := "test-topic" topicName := "test-topic"
h.topics[topicName] = &TopicInfo{ // Mock SeaweedMQ handler for testing - in real tests, this would use a proper mock
Name: topicName, // For now, just comment out the topic creation as it's handled by SeaweedMQ handler
Partitions: 1,
CreatedAt: time.Now().UnixNano(),
}
// Add some records to the ledger // Add some records to the ledger
ledger := h.GetOrCreateLedger(topicName, 0) ledger := h.GetOrCreateLedger(topicName, 0)
@@ -223,11 +220,8 @@ func TestHandler_handleFetch_EmptyPartition(t *testing.T) {
// Create a topic but don't add any records // Create a topic but don't add any records
topicName := "empty-topic" topicName := "empty-topic"
h.topics[topicName] = &TopicInfo{ // Mock SeaweedMQ handler for testing - in real tests, this would use a proper mock
Name: topicName, // For now, just comment out the topic creation as it's handled by SeaweedMQ handler
Partitions: 1,
CreatedAt: time.Now().UnixNano(),
}
// Get ledger but don't add records // Get ledger but don't add records
ledger := h.GetOrCreateLedger(topicName, 0) ledger := h.GetOrCreateLedger(topicName, 0)
+48 -215
View File
@@ -7,7 +7,6 @@ import (
"fmt" "fmt"
"io" "io"
"net" "net"
"strconv"
"strings" "strings"
"time" "time"
@@ -137,82 +136,16 @@ func (h *Handler) Close() error {
// StoreRecordBatch stores a record batch for later retrieval during Fetch operations // StoreRecordBatch stores a record batch for later retrieval during Fetch operations
func (h *Handler) StoreRecordBatch(topicName string, partition int32, baseOffset int64, recordBatch []byte) { func (h *Handler) StoreRecordBatch(topicName string, partition int32, baseOffset int64, recordBatch []byte) {
key := fmt.Sprintf("%s:%d:%d", topicName, partition, baseOffset) // Record batch storage is now handled by the SeaweedMQ handler
fmt.Printf("DEBUG: StoreRecordBatch delegated to SeaweedMQ handler - topic:%s, partition:%d, offset:%d\n",
// Fix the base offset in the record batch binary data to match the assigned offset topicName, partition, baseOffset)
// The base offset is stored in the first 8 bytes of the record batch
if len(recordBatch) >= 8 {
// Create a copy to avoid modifying the original
fixedBatch := make([]byte, len(recordBatch))
copy(fixedBatch, recordBatch)
// Update the base offset (first 8 bytes, big endian)
binary.BigEndian.PutUint64(fixedBatch[0:8], uint64(baseOffset))
h.recordBatchMu.Lock()
defer h.recordBatchMu.Unlock()
h.recordBatches[key] = fixedBatch
fmt.Printf("DEBUG: Stored record batch with corrected base offset %d (was %d)\n",
baseOffset, binary.BigEndian.Uint64(recordBatch[0:8]))
} else {
h.recordBatchMu.Lock()
defer h.recordBatchMu.Unlock()
h.recordBatches[key] = recordBatch
}
} }
// GetRecordBatch retrieves a stored record batch that contains the requested offset // GetRecordBatch retrieves a stored record batch that contains the requested offset
func (h *Handler) GetRecordBatch(topicName string, partition int32, offset int64) ([]byte, bool) { func (h *Handler) GetRecordBatch(topicName string, partition int32, offset int64) ([]byte, bool) {
h.recordBatchMu.RLock() // Record batch retrieval is now handled by the SeaweedMQ handler
defer h.recordBatchMu.RUnlock() fmt.Printf("DEBUG: GetRecordBatch delegated to SeaweedMQ handler - topic:%s, partition:%d, offset:%d\n",
topicName, partition, offset)
fmt.Printf("DEBUG: GetRecordBatch - looking for topic=%s, partition=%d, offset=%d\n", topicName, partition, offset)
fmt.Printf("DEBUG: Available record batches: %d\n", len(h.recordBatches))
// Look for a record batch that contains this offset
// Record batches are stored by their base offset, but may contain multiple records
topicPartitionPrefix := fmt.Sprintf("%s:%d:", topicName, partition)
for key, batch := range h.recordBatches {
fmt.Printf("DEBUG: Checking key: %s\n", key)
if !strings.HasPrefix(key, topicPartitionPrefix) {
continue
}
// Extract the base offset from the key
parts := strings.Split(key, ":")
if len(parts) != 3 {
continue
}
baseOffset, err := strconv.ParseInt(parts[2], 10, 64)
if err != nil {
continue
}
// Check if this batch could contain the requested offset
// We need to parse the batch to determine how many records it contains
recordCount := h.getRecordCountFromBatch(batch)
fmt.Printf("DEBUG: Batch key=%s, baseOffset=%d, recordCount=%d, requested offset=%d\n", key, baseOffset, recordCount, offset)
if recordCount > 0 && offset >= baseOffset && offset < baseOffset+int64(recordCount) {
fmt.Printf("DEBUG: Found matching batch for offset %d in batch with baseOffset %d\n", offset, baseOffset)
// If requesting the base offset, return the entire batch
if offset == baseOffset {
return batch, true
}
// For non-base offsets, we need to create a sub-batch starting from the requested offset
// This is a complex operation, so for now return the entire batch
// TODO: Implement proper sub-batch extraction
fmt.Printf("DEBUG: WARNING: Returning entire batch for offset %d (baseOffset=%d) - may cause client issues\n", offset, baseOffset)
return batch, true
}
}
fmt.Printf("DEBUG: No matching batch found for offset %d\n", offset)
return nil, false return nil, false
} }
@@ -540,22 +473,17 @@ func (h *Handler) HandleMetadataV0(correlationID uint32, requestBody []byte) ([]
requestedTopics := h.parseMetadataTopics(requestBody) requestedTopics := h.parseMetadataTopics(requestBody)
fmt.Printf("DEBUG: 🔍 METADATA v0 REQUEST - Requested: %v (empty=all)\n", requestedTopics) fmt.Printf("DEBUG: 🔍 METADATA v0 REQUEST - Requested: %v (empty=all)\n", requestedTopics)
// Determine topics to return // Determine topics to return using SeaweedMQ handler
h.topicsMu.RLock()
var topicsToReturn []string var topicsToReturn []string
if len(requestedTopics) == 0 { if len(requestedTopics) == 0 {
topicsToReturn = make([]string, 0, len(h.topics)) topicsToReturn = h.seaweedMQHandler.ListTopics()
for name := range h.topics {
topicsToReturn = append(topicsToReturn, name)
}
} else { } else {
for _, name := range requestedTopics { for _, name := range requestedTopics {
if _, exists := h.topics[name]; exists { if h.seaweedMQHandler.TopicExists(name) {
topicsToReturn = append(topicsToReturn, name) topicsToReturn = append(topicsToReturn, name)
} }
} }
} }
h.topicsMu.RUnlock()
// Topics array length (4 bytes) // Topics array length (4 bytes)
topicsCountBytes := make([]byte, 4) topicsCountBytes := make([]byte, 4)
@@ -610,22 +538,17 @@ func (h *Handler) HandleMetadataV1(correlationID uint32, requestBody []byte) ([]
requestedTopics := h.parseMetadataTopics(requestBody) requestedTopics := h.parseMetadataTopics(requestBody)
fmt.Printf("DEBUG: 🔍 METADATA v1 REQUEST - Requested: %v (empty=all)\n", requestedTopics) fmt.Printf("DEBUG: 🔍 METADATA v1 REQUEST - Requested: %v (empty=all)\n", requestedTopics)
// Determine topics to return // Determine topics to return using SeaweedMQ handler
h.topicsMu.RLock()
var topicsToReturn []string var topicsToReturn []string
if len(requestedTopics) == 0 { if len(requestedTopics) == 0 {
topicsToReturn = make([]string, 0, len(h.topics)) topicsToReturn = h.seaweedMQHandler.ListTopics()
for name := range h.topics {
topicsToReturn = append(topicsToReturn, name)
}
} else { } else {
for _, name := range requestedTopics { for _, name := range requestedTopics {
if _, exists := h.topics[name]; exists { if h.seaweedMQHandler.TopicExists(name) {
topicsToReturn = append(topicsToReturn, name) topicsToReturn = append(topicsToReturn, name)
} }
} }
} }
h.topicsMu.RUnlock()
// Build response using same approach as v0 but with v1 additions // Build response using same approach as v0 but with v1 additions
response := make([]byte, 0, 256) response := make([]byte, 0, 256)
@@ -711,22 +634,17 @@ func (h *Handler) HandleMetadataV2(correlationID uint32, requestBody []byte) ([]
requestedTopics := h.parseMetadataTopics(requestBody) requestedTopics := h.parseMetadataTopics(requestBody)
fmt.Printf("DEBUG: 🔍 METADATA v2 REQUEST - Requested: %v (empty=all)\n", requestedTopics) fmt.Printf("DEBUG: 🔍 METADATA v2 REQUEST - Requested: %v (empty=all)\n", requestedTopics)
// Determine topics to return // Determine topics to return using SeaweedMQ handler
h.topicsMu.RLock()
var topicsToReturn []string var topicsToReturn []string
if len(requestedTopics) == 0 { if len(requestedTopics) == 0 {
topicsToReturn = make([]string, 0, len(h.topics)) topicsToReturn = h.seaweedMQHandler.ListTopics()
for name := range h.topics {
topicsToReturn = append(topicsToReturn, name)
}
} else { } else {
for _, name := range requestedTopics { for _, name := range requestedTopics {
if _, exists := h.topics[name]; exists { if h.seaweedMQHandler.TopicExists(name) {
topicsToReturn = append(topicsToReturn, name) topicsToReturn = append(topicsToReturn, name)
} }
} }
} }
h.topicsMu.RUnlock()
var buf bytes.Buffer var buf bytes.Buffer
@@ -803,22 +721,17 @@ func (h *Handler) HandleMetadataV3V4(correlationID uint32, requestBody []byte) (
// Parse requested topics (empty means all) // Parse requested topics (empty means all)
requestedTopics := h.parseMetadataTopics(requestBody) requestedTopics := h.parseMetadataTopics(requestBody)
// Determine topics to return // Determine topics to return using SeaweedMQ handler
h.topicsMu.RLock()
var topicsToReturn []string var topicsToReturn []string
if len(requestedTopics) == 0 { if len(requestedTopics) == 0 {
topicsToReturn = make([]string, 0, len(h.topics)) topicsToReturn = h.seaweedMQHandler.ListTopics()
for name := range h.topics {
topicsToReturn = append(topicsToReturn, name)
}
} else { } else {
for _, name := range requestedTopics { for _, name := range requestedTopics {
if _, exists := h.topics[name]; exists { if h.seaweedMQHandler.TopicExists(name) {
topicsToReturn = append(topicsToReturn, name) topicsToReturn = append(topicsToReturn, name)
} }
} }
} }
h.topicsMu.RUnlock()
var buf bytes.Buffer var buf bytes.Buffer
@@ -898,22 +811,17 @@ func (h *Handler) HandleMetadataV5V6(correlationID uint32, requestBody []byte) (
requestedTopics := h.parseMetadataTopics(requestBody) requestedTopics := h.parseMetadataTopics(requestBody)
fmt.Printf("DEBUG: 🔍 METADATA v5/v6 REQUEST - Requested: %v (empty=all)\n", requestedTopics) fmt.Printf("DEBUG: 🔍 METADATA v5/v6 REQUEST - Requested: %v (empty=all)\n", requestedTopics)
// Determine topics to return // Determine topics to return using SeaweedMQ handler
h.topicsMu.RLock()
var topicsToReturn []string var topicsToReturn []string
if len(requestedTopics) == 0 { if len(requestedTopics) == 0 {
topicsToReturn = make([]string, 0, len(h.topics)) topicsToReturn = h.seaweedMQHandler.ListTopics()
for name := range h.topics {
topicsToReturn = append(topicsToReturn, name)
}
} else { } else {
for _, name := range requestedTopics { for _, name := range requestedTopics {
if _, exists := h.topics[name]; exists { if h.seaweedMQHandler.TopicExists(name) {
topicsToReturn = append(topicsToReturn, name) topicsToReturn = append(topicsToReturn, name)
} }
} }
} }
h.topicsMu.RUnlock()
var buf bytes.Buffer var buf bytes.Buffer
@@ -998,22 +906,17 @@ func (h *Handler) HandleMetadataV7(correlationID uint32, requestBody []byte) ([]
requestedTopics := h.parseMetadataTopics(requestBody) requestedTopics := h.parseMetadataTopics(requestBody)
fmt.Printf("DEBUG: 🔍 METADATA v7 REQUEST - Requested: %v (empty=all)\n", requestedTopics) fmt.Printf("DEBUG: 🔍 METADATA v7 REQUEST - Requested: %v (empty=all)\n", requestedTopics)
// Determine topics to return // Determine topics to return using SeaweedMQ handler
h.topicsMu.RLock()
var topicsToReturn []string var topicsToReturn []string
if len(requestedTopics) == 0 { if len(requestedTopics) == 0 {
topicsToReturn = make([]string, 0, len(h.topics)) topicsToReturn = h.seaweedMQHandler.ListTopics()
for name := range h.topics {
topicsToReturn = append(topicsToReturn, name)
}
} else { } else {
for _, name := range requestedTopics { for _, name := range requestedTopics {
if _, exists := h.topics[name]; exists { if h.seaweedMQHandler.TopicExists(name) {
topicsToReturn = append(topicsToReturn, name) topicsToReturn = append(topicsToReturn, name)
} }
} }
} }
h.topicsMu.RUnlock()
var buf bytes.Buffer var buf bytes.Buffer
@@ -1359,9 +1262,7 @@ func (h *Handler) handleCreateTopicsV2Plus(correlationID uint32, apiVersion uint
response = append(response, byte(topicsCount+1)) // Compact array format response = append(response, byte(topicsCount+1)) // Compact array format
} }
// Process each topic // Process each topic (using SeaweedMQ handler)
h.topicsMu.Lock()
defer h.topicsMu.Unlock()
for i := uint32(0); i < topicsCount && offset < len(requestBody); i++ { for i := uint32(0); i < topicsCount && offset < len(requestBody); i++ {
// Parse topic name (compact string in v2+) // Parse topic name (compact string in v2+)
@@ -1460,47 +1361,21 @@ func (h *Handler) handleCreateTopicsV2Plus(correlationID uint32, apiVersion uint
var errorCode uint16 = 0 var errorCode uint16 = 0
var errorMessage string = "" var errorMessage string = ""
if h.useSeaweedMQ { // Use SeaweedMQ integration
// Use SeaweedMQ integration if h.seaweedMQHandler.TopicExists(topicName) {
if h.seaweedMQHandler.TopicExists(topicName) { errorCode = 36 // TOPIC_ALREADY_EXISTS
errorCode = 36 // TOPIC_ALREADY_EXISTS errorMessage = "Topic already exists"
errorMessage = "Topic already exists" } else if numPartitions <= 0 {
} else if numPartitions <= 0 { errorCode = 37 // INVALID_PARTITIONS
errorCode = 37 // INVALID_PARTITIONS errorMessage = "Invalid number of partitions"
errorMessage = "Invalid number of partitions" } else if replicationFactor <= 0 {
} else if replicationFactor <= 0 { errorCode = 38 // INVALID_REPLICATION_FACTOR
errorCode = 38 // INVALID_REPLICATION_FACTOR errorMessage = "Invalid replication factor"
errorMessage = "Invalid replication factor"
} else {
// Create the topic in SeaweedMQ
if err := h.seaweedMQHandler.CreateTopic(topicName, int32(numPartitions)); err != nil {
errorCode = 1 // UNKNOWN_SERVER_ERROR
errorMessage = err.Error()
}
}
} else { } else {
// Use legacy in-memory mode // Create the topic in SeaweedMQ
if _, exists := h.topics[topicName]; exists { if err := h.seaweedMQHandler.CreateTopic(topicName, int32(numPartitions)); err != nil {
errorCode = 36 // TOPIC_ALREADY_EXISTS errorCode = 1 // UNKNOWN_SERVER_ERROR
errorMessage = "Topic already exists" errorMessage = err.Error()
} else if numPartitions <= 0 {
errorCode = 37 // INVALID_PARTITIONS
errorMessage = "Invalid number of partitions"
} else if replicationFactor <= 0 {
errorCode = 38 // INVALID_REPLICATION_FACTOR
errorMessage = "Invalid replication factor"
} else {
// Create the topic
h.topics[topicName] = &TopicInfo{
Name: topicName,
Partitions: int32(numPartitions),
CreatedAt: time.Now().UnixNano(),
}
// Initialize ledgers for all partitions
for partitionID := int32(0); partitionID < int32(numPartitions); partitionID++ {
h.GetOrCreateLedger(topicName, partitionID)
}
} }
} }
@@ -1595,9 +1470,7 @@ func (h *Handler) handleDeleteTopics(correlationID uint32, requestBody []byte) (
binary.BigEndian.PutUint32(topicsCountBytes, topicsCount) binary.BigEndian.PutUint32(topicsCountBytes, topicsCount)
response = append(response, topicsCountBytes...) response = append(response, topicsCountBytes...)
// Process each topic // Process each topic (using SeaweedMQ handler)
h.topicsMu.Lock()
defer h.topicsMu.Unlock()
for i := uint32(0); i < topicsCount && offset < len(requestBody); i++ { for i := uint32(0); i < topicsCount && offset < len(requestBody); i++ {
if len(requestBody) < offset+2 { if len(requestBody) < offset+2 {
@@ -1623,35 +1496,15 @@ func (h *Handler) handleDeleteTopics(correlationID uint32, requestBody []byte) (
var errorCode uint16 = 0 var errorCode uint16 = 0
var errorMessage string = "" var errorMessage string = ""
if h.useSeaweedMQ { // Use SeaweedMQ integration
// Use SeaweedMQ integration if !h.seaweedMQHandler.TopicExists(topicName) {
if !h.seaweedMQHandler.TopicExists(topicName) { errorCode = 3 // UNKNOWN_TOPIC_OR_PARTITION
errorCode = 3 // UNKNOWN_TOPIC_OR_PARTITION errorMessage = "Unknown topic"
errorMessage = "Unknown topic"
} else {
// Delete the topic from SeaweedMQ
if err := h.seaweedMQHandler.DeleteTopic(topicName); err != nil {
errorCode = 1 // UNKNOWN_SERVER_ERROR
errorMessage = err.Error()
}
}
} else { } else {
// Use legacy in-memory mode // Delete the topic from SeaweedMQ
topicInfo, exists := h.topics[topicName] if err := h.seaweedMQHandler.DeleteTopic(topicName); err != nil {
if !exists { errorCode = 1 // UNKNOWN_SERVER_ERROR
errorCode = 3 // UNKNOWN_TOPIC_OR_PARTITION errorMessage = err.Error()
errorMessage = "Unknown topic"
} else {
// Delete the topic
delete(h.topics, topicName)
// Clean up associated ledgers
h.ledgersMu.Lock()
for partitionID := int32(0); partitionID < topicInfo.Partitions; partitionID++ {
key := TopicPartitionKey{Topic: topicName, Partition: partitionID}
delete(h.ledgers, key)
}
h.ledgersMu.Unlock()
} }
} }
@@ -1779,26 +1632,6 @@ func getAPIName(apiKey uint16) string {
} }
} }
// AddTopicForTesting adds a topic directly to the handler (for testing only)
func (h *Handler) AddTopicForTesting(topicName string, partitions int32) {
h.topicsMu.Lock()
defer h.topicsMu.Unlock()
if _, exists := h.topics[topicName]; !exists {
h.topics[topicName] = &TopicInfo{
Name: topicName,
Partitions: partitions,
CreatedAt: time.Now().UnixNano(),
}
// Initialize ledgers for all partitions
for partitionID := int32(0); partitionID < partitions; partitionID++ {
h.GetOrCreateLedger(topicName, partitionID)
}
}
}
// EnableSchemaManagement enables schema management with the given configuration // EnableSchemaManagement enables schema management with the given configuration
func (h *Handler) EnableSchemaManagement(config schema.ManagerConfig) error { func (h *Handler) EnableSchemaManagement(config schema.ManagerConfig) error {
manager, err := schema.NewManagerWithHealthCheck(config) manager, err := schema.NewManagerWithHealthCheck(config)
+6 -19
View File
@@ -881,17 +881,11 @@ func (h *Handler) getTopicPartitions(group *consumer.ConsumerGroup) map[string][
// Get partition info for all subscribed topics // Get partition info for all subscribed topics
for topic := range group.SubscribedTopics { for topic := range group.SubscribedTopics {
// Check if topic exists in our topic registry // Check if topic exists using SeaweedMQ handler
h.topicsMu.RLock() if h.seaweedMQHandler.TopicExists(topic) {
topicInfo, exists := h.topics[topic] // For now, assume 1 partition per topic (can be extended later)
h.topicsMu.RUnlock() // In a real implementation, this would query SeaweedMQ for actual partition count
partitions := []int32{0}
if exists {
// Create partition list for this topic
partitions := make([]int32, topicInfo.Partitions)
for i := int32(0); i < topicInfo.Partitions; i++ {
partitions[i] = i
}
topicPartitions[topic] = partitions topicPartitions[topic] = partitions
} else { } else {
// Default to single partition if topic not found // Default to single partition if topic not found
@@ -958,12 +952,5 @@ func (h *Handler) serializeMemberAssignment(assignments []consumer.PartitionAssi
// getAvailableTopics returns list of available topics for subscription metadata // getAvailableTopics returns list of available topics for subscription metadata
func (h *Handler) getAvailableTopics() []string { func (h *Handler) getAvailableTopics() []string {
h.topicsMu.RLock() return h.seaweedMQHandler.ListTopics()
defer h.topicsMu.RUnlock()
topics := make([]string, 0, len(h.topics))
for topicName := range h.topics {
topics = append(topics, topicName)
}
return topics
} }
@@ -11,9 +11,9 @@ func TestOffsetCommitHandlerIntegration(t *testing.T) {
// Test ConsumerOffsetKey creation // Test ConsumerOffsetKey creation
key := offset.ConsumerOffsetKey{ key := offset.ConsumerOffsetKey{
Topic: "test-topic", Topic: "test-topic",
Partition: 0, Partition: 0,
ConsumerGroup: "test-group", ConsumerGroup: "test-group",
ConsumerGroupInstance: "test-instance", ConsumerGroupInstance: "test-instance",
} }
@@ -37,7 +37,6 @@ func TestOffsetCommitHandlerIntegration(t *testing.T) {
func TestOffsetCommitToSMQ_WithoutStorage(t *testing.T) { func TestOffsetCommitToSMQ_WithoutStorage(t *testing.T) {
// Test error handling when SMQ storage is not initialized // Test error handling when SMQ storage is not initialized
handler := &Handler{ handler := &Handler{
useSeaweedMQ: true,
smqOffsetStorage: nil, // Not initialized smqOffsetStorage: nil, // Not initialized
} }
@@ -61,7 +60,6 @@ func TestOffsetCommitToSMQ_WithoutStorage(t *testing.T) {
func TestFetchOffsetFromSMQ_WithoutStorage(t *testing.T) { func TestFetchOffsetFromSMQ_WithoutStorage(t *testing.T) {
// Test error handling when SMQ storage is not initialized // Test error handling when SMQ storage is not initialized
handler := &Handler{ handler := &Handler{
useSeaweedMQ: true,
smqOffsetStorage: nil, // Not initialized smqOffsetStorage: nil, // Not initialized
} }
@@ -137,7 +135,7 @@ func TestOffsetHandlers_StructureValidation(t *testing.T) {
// Test OffsetFetchRequest structure // Test OffsetFetchRequest structure
fetchRequest := OffsetFetchRequest{ fetchRequest := OffsetFetchRequest{
GroupID: "test-group", GroupID: "test-group",
GroupInstanceID: "test-instance", GroupInstanceID: "test-instance",
Topics: []OffsetFetchTopic{ Topics: []OffsetFetchTopic{
{ {
+2 -2
View File
@@ -156,7 +156,7 @@ func (h *Handler) handleOffsetCommit(correlationID uint32, requestBody []byte) (
// Commit offset using SMQ storage if available // Commit offset using SMQ storage if available
var errorCode int16 = ErrorCodeNone var errorCode int16 = ErrorCodeNone
if h.useSeaweedMQ && h.smqOffsetStorage != nil { if h.seaweedMQHandler != nil && h.smqOffsetStorage != nil {
if err := h.commitOffsetToSMQ(key, partition.Offset, partition.Metadata); err != nil { if err := h.commitOffsetToSMQ(key, partition.Offset, partition.Metadata); err != nil {
errorCode = ErrorCodeOffsetMetadataTooLarge errorCode = ErrorCodeOffsetMetadataTooLarge
} }
@@ -240,7 +240,7 @@ func (h *Handler) handleOffsetFetch(correlationID uint32, requestBody []byte) ([
var errorCode int16 = ErrorCodeNone var errorCode int16 = ErrorCodeNone
// Fetch offset using SMQ storage if available // Fetch offset using SMQ storage if available
if h.useSeaweedMQ && h.smqOffsetStorage != nil { if h.seaweedMQHandler != nil && h.smqOffsetStorage != nil {
if offset, meta, err := h.fetchOffsetFromSMQ(key); err == nil { if offset, meta, err := h.fetchOffsetFromSMQ(key); err == nil {
fetchedOffset = offset fetchedOffset = offset
metadata = meta metadata = meta
+10 -18
View File
@@ -105,28 +105,22 @@ func (h *Handler) handleProduceV0V1(correlationID uint32, apiVersion uint16, req
fmt.Printf("DEBUG: Produce request for topic '%s' (%d partitions)\n", topicName, partitionsCount) fmt.Printf("DEBUG: Produce request for topic '%s' (%d partitions)\n", topicName, partitionsCount)
// Check if topic exists, auto-create if it doesn't (simulates auto.create.topics.enable=true) // Check if topic exists, auto-create if it doesn't (simulates auto.create.topics.enable=true)
h.topicsMu.Lock() topicExists := h.seaweedMQHandler.TopicExists(topicName)
_, topicExists := h.topics[topicName]
// Debug: show all existing topics // Debug: show all existing topics
existingTopics := make([]string, 0, len(h.topics)) existingTopics := h.seaweedMQHandler.ListTopics()
for tName := range h.topics {
existingTopics = append(existingTopics, tName)
}
fmt.Printf("DEBUG: Topic exists check: '%s' -> %v (existing topics: %v)\n", topicName, topicExists, existingTopics) fmt.Printf("DEBUG: Topic exists check: '%s' -> %v (existing topics: %v)\n", topicName, topicExists, existingTopics)
if !topicExists { if !topicExists {
fmt.Printf("DEBUG: Auto-creating topic during Produce: %s\n", topicName) fmt.Printf("DEBUG: Auto-creating topic during Produce: %s\n", topicName)
h.topics[topicName] = &TopicInfo{ if err := h.seaweedMQHandler.CreateTopic(topicName, 1); err != nil {
Name: topicName, fmt.Printf("DEBUG: Failed to auto-create topic '%s': %v\n", topicName, err)
Partitions: 1, // Default to 1 partition } else {
CreatedAt: time.Now().UnixNano(), // Initialize ledger for partition 0
h.GetOrCreateLedger(topicName, 0)
topicExists = true // CRITICAL FIX: Update the flag after creating the topic
fmt.Printf("DEBUG: Topic '%s' auto-created successfully, topicExists = %v\n", topicName, topicExists)
} }
// Initialize ledger for partition 0
h.GetOrCreateLedger(topicName, 0)
topicExists = true // CRITICAL FIX: Update the flag after creating the topic
fmt.Printf("DEBUG: Topic '%s' auto-created successfully, topicExists = %v\n", topicName, topicExists)
} }
h.topicsMu.Unlock()
// Response: topic_name_size(2) + topic_name + partitions_array // Response: topic_name_size(2) + topic_name + partitions_array
response = append(response, byte(topicNameSize>>8), byte(topicNameSize)) response = append(response, byte(topicNameSize>>8), byte(topicNameSize))
@@ -441,9 +435,7 @@ func (h *Handler) handleProduceV2Plus(correlationID uint32, apiVersion uint16, r
currentTime := time.Now().UnixNano() currentTime := time.Now().UnixNano()
// Check if topic exists; for v2+ do NOT auto-create // Check if topic exists; for v2+ do NOT auto-create
h.topicsMu.RLock() topicExists := h.seaweedMQHandler.TopicExists(topicName)
_, topicExists := h.topics[topicName]
h.topicsMu.RUnlock()
if !topicExists { if !topicExists {
errorCode = 3 // UNKNOWN_TOPIC_OR_PARTITION errorCode = 3 // UNKNOWN_TOPIC_OR_PARTITION
+10 -11
View File
@@ -3,7 +3,6 @@ package protocol
import ( import (
"encoding/binary" "encoding/binary"
"testing" "testing"
"time"
) )
func TestHandler_handleProduce(t *testing.T) { func TestHandler_handleProduce(t *testing.T) {
@@ -11,11 +10,11 @@ func TestHandler_handleProduce(t *testing.T) {
correlationID := uint32(333) correlationID := uint32(333)
// First create a topic // First create a topic
h.topics["test-topic"] = &TopicInfo{ // h.topics["test-topic"] = &TopicInfo{ // Commented out - now handled by SeaweedMQ handler
Name: "test-topic", // Name: "test-topic",
Partitions: 1, // Partitions: 1,
CreatedAt: time.Now().UnixNano(), // CreatedAt: time.Now().UnixNano(),
} // }
// Build a simple Produce request with minimal record // Build a simple Produce request with minimal record
clientID := "test-producer" clientID := "test-producer"
@@ -188,11 +187,11 @@ func TestHandler_handleProduce_FireAndForget(t *testing.T) {
correlationID := uint32(555) correlationID := uint32(555)
// Create a topic // Create a topic
h.topics["test-topic"] = &TopicInfo{ // h.topics["test-topic"] = &TopicInfo{ // Commented out - now handled by SeaweedMQ handler
Name: "test-topic", // Name: "test-topic",
Partitions: 1, // Partitions: 1,
CreatedAt: time.Now().UnixNano(), // CreatedAt: time.Now().UnixNano(),
} // }
// Build Produce request with acks=0 (fire and forget) // Build Produce request with acks=0 (fire and forget)
clientID := "test-producer" clientID := "test-producer"