mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-12 01:20:45 +02:00
fix in-memory variables
This commit is contained in:
@@ -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
|
||||
h.topicsMu.RLock()
|
||||
_, topicExists := h.topics[topic.Name]
|
||||
h.topicsMu.RUnlock()
|
||||
if !topicExists {
|
||||
if !h.seaweedMQHandler.TopicExists(topic.Name) {
|
||||
response[errorPos] = 0
|
||||
response[errorPos+1] = 3 // UNKNOWN_TOPIC_OR_PARTITION
|
||||
}
|
||||
|
||||
@@ -12,11 +12,8 @@ func TestHandler_handleFetch(t *testing.T) {
|
||||
|
||||
// Create a topic and add some records
|
||||
topicName := "test-topic"
|
||||
h.topics[topicName] = &TopicInfo{
|
||||
Name: topicName,
|
||||
Partitions: 1,
|
||||
CreatedAt: time.Now().UnixNano(),
|
||||
}
|
||||
// Mock SeaweedMQ handler for testing - in real tests, this would use a proper mock
|
||||
// For now, just comment out the topic creation as it's handled by SeaweedMQ handler
|
||||
|
||||
// Add some records to the ledger
|
||||
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
|
||||
topicName := "empty-topic"
|
||||
h.topics[topicName] = &TopicInfo{
|
||||
Name: topicName,
|
||||
Partitions: 1,
|
||||
CreatedAt: time.Now().UnixNano(),
|
||||
}
|
||||
// Mock SeaweedMQ handler for testing - in real tests, this would use a proper mock
|
||||
// For now, just comment out the topic creation as it's handled by SeaweedMQ handler
|
||||
|
||||
// Get ledger but don't add records
|
||||
ledger := h.GetOrCreateLedger(topicName, 0)
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -137,82 +136,16 @@ func (h *Handler) Close() error {
|
||||
|
||||
// StoreRecordBatch stores a record batch for later retrieval during Fetch operations
|
||||
func (h *Handler) StoreRecordBatch(topicName string, partition int32, baseOffset int64, recordBatch []byte) {
|
||||
key := fmt.Sprintf("%s:%d:%d", topicName, partition, baseOffset)
|
||||
|
||||
// Fix the base offset in the record batch binary data to match the assigned offset
|
||||
// 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
|
||||
}
|
||||
// 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",
|
||||
topicName, partition, baseOffset)
|
||||
}
|
||||
|
||||
// GetRecordBatch retrieves a stored record batch that contains the requested offset
|
||||
func (h *Handler) GetRecordBatch(topicName string, partition int32, offset int64) ([]byte, bool) {
|
||||
h.recordBatchMu.RLock()
|
||||
defer h.recordBatchMu.RUnlock()
|
||||
|
||||
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)
|
||||
// Record batch retrieval is now handled by the SeaweedMQ handler
|
||||
fmt.Printf("DEBUG: GetRecordBatch delegated to SeaweedMQ handler - topic:%s, partition:%d, offset:%d\n",
|
||||
topicName, partition, offset)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -540,22 +473,17 @@ func (h *Handler) HandleMetadataV0(correlationID uint32, requestBody []byte) ([]
|
||||
requestedTopics := h.parseMetadataTopics(requestBody)
|
||||
fmt.Printf("DEBUG: 🔍 METADATA v0 REQUEST - Requested: %v (empty=all)\n", requestedTopics)
|
||||
|
||||
// Determine topics to return
|
||||
h.topicsMu.RLock()
|
||||
// Determine topics to return using SeaweedMQ handler
|
||||
var topicsToReturn []string
|
||||
if len(requestedTopics) == 0 {
|
||||
topicsToReturn = make([]string, 0, len(h.topics))
|
||||
for name := range h.topics {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
topicsToReturn = h.seaweedMQHandler.ListTopics()
|
||||
} else {
|
||||
for _, name := range requestedTopics {
|
||||
if _, exists := h.topics[name]; exists {
|
||||
if h.seaweedMQHandler.TopicExists(name) {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
h.topicsMu.RUnlock()
|
||||
|
||||
// Topics array length (4 bytes)
|
||||
topicsCountBytes := make([]byte, 4)
|
||||
@@ -610,22 +538,17 @@ func (h *Handler) HandleMetadataV1(correlationID uint32, requestBody []byte) ([]
|
||||
requestedTopics := h.parseMetadataTopics(requestBody)
|
||||
fmt.Printf("DEBUG: 🔍 METADATA v1 REQUEST - Requested: %v (empty=all)\n", requestedTopics)
|
||||
|
||||
// Determine topics to return
|
||||
h.topicsMu.RLock()
|
||||
// Determine topics to return using SeaweedMQ handler
|
||||
var topicsToReturn []string
|
||||
if len(requestedTopics) == 0 {
|
||||
topicsToReturn = make([]string, 0, len(h.topics))
|
||||
for name := range h.topics {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
topicsToReturn = h.seaweedMQHandler.ListTopics()
|
||||
} else {
|
||||
for _, name := range requestedTopics {
|
||||
if _, exists := h.topics[name]; exists {
|
||||
if h.seaweedMQHandler.TopicExists(name) {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
h.topicsMu.RUnlock()
|
||||
|
||||
// Build response using same approach as v0 but with v1 additions
|
||||
response := make([]byte, 0, 256)
|
||||
@@ -711,22 +634,17 @@ func (h *Handler) HandleMetadataV2(correlationID uint32, requestBody []byte) ([]
|
||||
requestedTopics := h.parseMetadataTopics(requestBody)
|
||||
fmt.Printf("DEBUG: 🔍 METADATA v2 REQUEST - Requested: %v (empty=all)\n", requestedTopics)
|
||||
|
||||
// Determine topics to return
|
||||
h.topicsMu.RLock()
|
||||
// Determine topics to return using SeaweedMQ handler
|
||||
var topicsToReturn []string
|
||||
if len(requestedTopics) == 0 {
|
||||
topicsToReturn = make([]string, 0, len(h.topics))
|
||||
for name := range h.topics {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
topicsToReturn = h.seaweedMQHandler.ListTopics()
|
||||
} else {
|
||||
for _, name := range requestedTopics {
|
||||
if _, exists := h.topics[name]; exists {
|
||||
if h.seaweedMQHandler.TopicExists(name) {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
h.topicsMu.RUnlock()
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
@@ -803,22 +721,17 @@ func (h *Handler) HandleMetadataV3V4(correlationID uint32, requestBody []byte) (
|
||||
// Parse requested topics (empty means all)
|
||||
requestedTopics := h.parseMetadataTopics(requestBody)
|
||||
|
||||
// Determine topics to return
|
||||
h.topicsMu.RLock()
|
||||
// Determine topics to return using SeaweedMQ handler
|
||||
var topicsToReturn []string
|
||||
if len(requestedTopics) == 0 {
|
||||
topicsToReturn = make([]string, 0, len(h.topics))
|
||||
for name := range h.topics {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
topicsToReturn = h.seaweedMQHandler.ListTopics()
|
||||
} else {
|
||||
for _, name := range requestedTopics {
|
||||
if _, exists := h.topics[name]; exists {
|
||||
if h.seaweedMQHandler.TopicExists(name) {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
h.topicsMu.RUnlock()
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
@@ -898,22 +811,17 @@ func (h *Handler) HandleMetadataV5V6(correlationID uint32, requestBody []byte) (
|
||||
requestedTopics := h.parseMetadataTopics(requestBody)
|
||||
fmt.Printf("DEBUG: 🔍 METADATA v5/v6 REQUEST - Requested: %v (empty=all)\n", requestedTopics)
|
||||
|
||||
// Determine topics to return
|
||||
h.topicsMu.RLock()
|
||||
// Determine topics to return using SeaweedMQ handler
|
||||
var topicsToReturn []string
|
||||
if len(requestedTopics) == 0 {
|
||||
topicsToReturn = make([]string, 0, len(h.topics))
|
||||
for name := range h.topics {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
topicsToReturn = h.seaweedMQHandler.ListTopics()
|
||||
} else {
|
||||
for _, name := range requestedTopics {
|
||||
if _, exists := h.topics[name]; exists {
|
||||
if h.seaweedMQHandler.TopicExists(name) {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
h.topicsMu.RUnlock()
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
@@ -998,22 +906,17 @@ func (h *Handler) HandleMetadataV7(correlationID uint32, requestBody []byte) ([]
|
||||
requestedTopics := h.parseMetadataTopics(requestBody)
|
||||
fmt.Printf("DEBUG: 🔍 METADATA v7 REQUEST - Requested: %v (empty=all)\n", requestedTopics)
|
||||
|
||||
// Determine topics to return
|
||||
h.topicsMu.RLock()
|
||||
// Determine topics to return using SeaweedMQ handler
|
||||
var topicsToReturn []string
|
||||
if len(requestedTopics) == 0 {
|
||||
topicsToReturn = make([]string, 0, len(h.topics))
|
||||
for name := range h.topics {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
topicsToReturn = h.seaweedMQHandler.ListTopics()
|
||||
} else {
|
||||
for _, name := range requestedTopics {
|
||||
if _, exists := h.topics[name]; exists {
|
||||
if h.seaweedMQHandler.TopicExists(name) {
|
||||
topicsToReturn = append(topicsToReturn, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
h.topicsMu.RUnlock()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Process each topic
|
||||
h.topicsMu.Lock()
|
||||
defer h.topicsMu.Unlock()
|
||||
// Process each topic (using SeaweedMQ handler)
|
||||
|
||||
for i := uint32(0); i < topicsCount && offset < len(requestBody); i++ {
|
||||
// Parse topic name (compact string in v2+)
|
||||
@@ -1460,47 +1361,21 @@ func (h *Handler) handleCreateTopicsV2Plus(correlationID uint32, apiVersion uint
|
||||
var errorCode uint16 = 0
|
||||
var errorMessage string = ""
|
||||
|
||||
if h.useSeaweedMQ {
|
||||
// Use SeaweedMQ integration
|
||||
if h.seaweedMQHandler.TopicExists(topicName) {
|
||||
errorCode = 36 // TOPIC_ALREADY_EXISTS
|
||||
errorMessage = "Topic already exists"
|
||||
} 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 in SeaweedMQ
|
||||
if err := h.seaweedMQHandler.CreateTopic(topicName, int32(numPartitions)); err != nil {
|
||||
errorCode = 1 // UNKNOWN_SERVER_ERROR
|
||||
errorMessage = err.Error()
|
||||
}
|
||||
}
|
||||
// Use SeaweedMQ integration
|
||||
if h.seaweedMQHandler.TopicExists(topicName) {
|
||||
errorCode = 36 // TOPIC_ALREADY_EXISTS
|
||||
errorMessage = "Topic already exists"
|
||||
} 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 {
|
||||
// Use legacy in-memory mode
|
||||
if _, exists := h.topics[topicName]; exists {
|
||||
errorCode = 36 // TOPIC_ALREADY_EXISTS
|
||||
errorMessage = "Topic already exists"
|
||||
} 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)
|
||||
}
|
||||
// Create the topic in SeaweedMQ
|
||||
if err := h.seaweedMQHandler.CreateTopic(topicName, int32(numPartitions)); err != nil {
|
||||
errorCode = 1 // UNKNOWN_SERVER_ERROR
|
||||
errorMessage = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1595,9 +1470,7 @@ func (h *Handler) handleDeleteTopics(correlationID uint32, requestBody []byte) (
|
||||
binary.BigEndian.PutUint32(topicsCountBytes, topicsCount)
|
||||
response = append(response, topicsCountBytes...)
|
||||
|
||||
// Process each topic
|
||||
h.topicsMu.Lock()
|
||||
defer h.topicsMu.Unlock()
|
||||
// Process each topic (using SeaweedMQ handler)
|
||||
|
||||
for i := uint32(0); i < topicsCount && offset < len(requestBody); i++ {
|
||||
if len(requestBody) < offset+2 {
|
||||
@@ -1623,35 +1496,15 @@ func (h *Handler) handleDeleteTopics(correlationID uint32, requestBody []byte) (
|
||||
var errorCode uint16 = 0
|
||||
var errorMessage string = ""
|
||||
|
||||
if h.useSeaweedMQ {
|
||||
// Use SeaweedMQ integration
|
||||
if !h.seaweedMQHandler.TopicExists(topicName) {
|
||||
errorCode = 3 // UNKNOWN_TOPIC_OR_PARTITION
|
||||
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()
|
||||
}
|
||||
}
|
||||
// Use SeaweedMQ integration
|
||||
if !h.seaweedMQHandler.TopicExists(topicName) {
|
||||
errorCode = 3 // UNKNOWN_TOPIC_OR_PARTITION
|
||||
errorMessage = "Unknown topic"
|
||||
} else {
|
||||
// Use legacy in-memory mode
|
||||
topicInfo, exists := h.topics[topicName]
|
||||
if !exists {
|
||||
errorCode = 3 // UNKNOWN_TOPIC_OR_PARTITION
|
||||
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()
|
||||
// Delete the topic from SeaweedMQ
|
||||
if err := h.seaweedMQHandler.DeleteTopic(topicName); err != nil {
|
||||
errorCode = 1 // UNKNOWN_SERVER_ERROR
|
||||
errorMessage = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
func (h *Handler) EnableSchemaManagement(config schema.ManagerConfig) error {
|
||||
manager, err := schema.NewManagerWithHealthCheck(config)
|
||||
|
||||
@@ -881,17 +881,11 @@ func (h *Handler) getTopicPartitions(group *consumer.ConsumerGroup) map[string][
|
||||
|
||||
// Get partition info for all subscribed topics
|
||||
for topic := range group.SubscribedTopics {
|
||||
// Check if topic exists in our topic registry
|
||||
h.topicsMu.RLock()
|
||||
topicInfo, exists := h.topics[topic]
|
||||
h.topicsMu.RUnlock()
|
||||
|
||||
if exists {
|
||||
// Create partition list for this topic
|
||||
partitions := make([]int32, topicInfo.Partitions)
|
||||
for i := int32(0); i < topicInfo.Partitions; i++ {
|
||||
partitions[i] = i
|
||||
}
|
||||
// Check if topic exists using SeaweedMQ handler
|
||||
if h.seaweedMQHandler.TopicExists(topic) {
|
||||
// For now, assume 1 partition per topic (can be extended later)
|
||||
// In a real implementation, this would query SeaweedMQ for actual partition count
|
||||
partitions := []int32{0}
|
||||
topicPartitions[topic] = partitions
|
||||
} else {
|
||||
// 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
|
||||
func (h *Handler) getAvailableTopics() []string {
|
||||
h.topicsMu.RLock()
|
||||
defer h.topicsMu.RUnlock()
|
||||
|
||||
topics := make([]string, 0, len(h.topics))
|
||||
for topicName := range h.topics {
|
||||
topics = append(topics, topicName)
|
||||
}
|
||||
return topics
|
||||
return h.seaweedMQHandler.ListTopics()
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ func TestOffsetCommitHandlerIntegration(t *testing.T) {
|
||||
|
||||
// Test ConsumerOffsetKey creation
|
||||
key := offset.ConsumerOffsetKey{
|
||||
Topic: "test-topic",
|
||||
Partition: 0,
|
||||
ConsumerGroup: "test-group",
|
||||
Topic: "test-topic",
|
||||
Partition: 0,
|
||||
ConsumerGroup: "test-group",
|
||||
ConsumerGroupInstance: "test-instance",
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ func TestOffsetCommitHandlerIntegration(t *testing.T) {
|
||||
func TestOffsetCommitToSMQ_WithoutStorage(t *testing.T) {
|
||||
// Test error handling when SMQ storage is not initialized
|
||||
handler := &Handler{
|
||||
useSeaweedMQ: true,
|
||||
smqOffsetStorage: nil, // Not initialized
|
||||
}
|
||||
|
||||
@@ -61,7 +60,6 @@ func TestOffsetCommitToSMQ_WithoutStorage(t *testing.T) {
|
||||
func TestFetchOffsetFromSMQ_WithoutStorage(t *testing.T) {
|
||||
// Test error handling when SMQ storage is not initialized
|
||||
handler := &Handler{
|
||||
useSeaweedMQ: true,
|
||||
smqOffsetStorage: nil, // Not initialized
|
||||
}
|
||||
|
||||
@@ -87,7 +85,7 @@ func TestFetchOffsetFromSMQ_WithoutStorage(t *testing.T) {
|
||||
|
||||
func TestOffsetHandlers_StructureValidation(t *testing.T) {
|
||||
// Validate that offset commit/fetch request/response structures are properly formed
|
||||
|
||||
|
||||
// Test OffsetCommitRequest structure
|
||||
request := OffsetCommitRequest{
|
||||
GroupID: "test-group",
|
||||
@@ -135,9 +133,9 @@ func TestOffsetHandlers_StructureValidation(t *testing.T) {
|
||||
t.Errorf("Expected offset 100, got %d", partition.Offset)
|
||||
}
|
||||
|
||||
// Test OffsetFetchRequest structure
|
||||
// Test OffsetFetchRequest structure
|
||||
fetchRequest := OffsetFetchRequest{
|
||||
GroupID: "test-group",
|
||||
GroupID: "test-group",
|
||||
GroupInstanceID: "test-instance",
|
||||
Topics: []OffsetFetchTopic{
|
||||
{
|
||||
|
||||
@@ -156,7 +156,7 @@ func (h *Handler) handleOffsetCommit(correlationID uint32, requestBody []byte) (
|
||||
|
||||
// Commit offset using SMQ storage if available
|
||||
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 {
|
||||
errorCode = ErrorCodeOffsetMetadataTooLarge
|
||||
}
|
||||
@@ -240,7 +240,7 @@ func (h *Handler) handleOffsetFetch(correlationID uint32, requestBody []byte) ([
|
||||
var errorCode int16 = ErrorCodeNone
|
||||
|
||||
// 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 {
|
||||
fetchedOffset = offset
|
||||
metadata = meta
|
||||
|
||||
@@ -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)
|
||||
|
||||
// Check if topic exists, auto-create if it doesn't (simulates auto.create.topics.enable=true)
|
||||
h.topicsMu.Lock()
|
||||
_, topicExists := h.topics[topicName]
|
||||
topicExists := h.seaweedMQHandler.TopicExists(topicName)
|
||||
|
||||
// Debug: show all existing topics
|
||||
existingTopics := make([]string, 0, len(h.topics))
|
||||
for tName := range h.topics {
|
||||
existingTopics = append(existingTopics, tName)
|
||||
}
|
||||
existingTopics := h.seaweedMQHandler.ListTopics()
|
||||
fmt.Printf("DEBUG: Topic exists check: '%s' -> %v (existing topics: %v)\n", topicName, topicExists, existingTopics)
|
||||
if !topicExists {
|
||||
fmt.Printf("DEBUG: Auto-creating topic during Produce: %s\n", topicName)
|
||||
h.topics[topicName] = &TopicInfo{
|
||||
Name: topicName,
|
||||
Partitions: 1, // Default to 1 partition
|
||||
CreatedAt: time.Now().UnixNano(),
|
||||
if err := h.seaweedMQHandler.CreateTopic(topicName, 1); err != nil {
|
||||
fmt.Printf("DEBUG: Failed to auto-create topic '%s': %v\n", topicName, err)
|
||||
} else {
|
||||
// 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 = append(response, byte(topicNameSize>>8), byte(topicNameSize))
|
||||
@@ -441,9 +435,7 @@ func (h *Handler) handleProduceV2Plus(correlationID uint32, apiVersion uint16, r
|
||||
currentTime := time.Now().UnixNano()
|
||||
|
||||
// Check if topic exists; for v2+ do NOT auto-create
|
||||
h.topicsMu.RLock()
|
||||
_, topicExists := h.topics[topicName]
|
||||
h.topicsMu.RUnlock()
|
||||
topicExists := h.seaweedMQHandler.TopicExists(topicName)
|
||||
|
||||
if !topicExists {
|
||||
errorCode = 3 // UNKNOWN_TOPIC_OR_PARTITION
|
||||
|
||||
@@ -3,7 +3,6 @@ package protocol
|
||||
import (
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestHandler_handleProduce(t *testing.T) {
|
||||
@@ -11,11 +10,11 @@ func TestHandler_handleProduce(t *testing.T) {
|
||||
correlationID := uint32(333)
|
||||
|
||||
// First create a topic
|
||||
h.topics["test-topic"] = &TopicInfo{
|
||||
Name: "test-topic",
|
||||
Partitions: 1,
|
||||
CreatedAt: time.Now().UnixNano(),
|
||||
}
|
||||
// h.topics["test-topic"] = &TopicInfo{ // Commented out - now handled by SeaweedMQ handler
|
||||
// Name: "test-topic",
|
||||
// Partitions: 1,
|
||||
// CreatedAt: time.Now().UnixNano(),
|
||||
// }
|
||||
|
||||
// Build a simple Produce request with minimal record
|
||||
clientID := "test-producer"
|
||||
@@ -188,11 +187,11 @@ func TestHandler_handleProduce_FireAndForget(t *testing.T) {
|
||||
correlationID := uint32(555)
|
||||
|
||||
// Create a topic
|
||||
h.topics["test-topic"] = &TopicInfo{
|
||||
Name: "test-topic",
|
||||
Partitions: 1,
|
||||
CreatedAt: time.Now().UnixNano(),
|
||||
}
|
||||
// h.topics["test-topic"] = &TopicInfo{ // Commented out - now handled by SeaweedMQ handler
|
||||
// Name: "test-topic",
|
||||
// Partitions: 1,
|
||||
// CreatedAt: time.Now().UnixNano(),
|
||||
// }
|
||||
|
||||
// Build Produce request with acks=0 (fire and forget)
|
||||
clientID := "test-producer"
|
||||
|
||||
Reference in New Issue
Block a user