Hard Stuck On Challenge #YG4

I’m stuck on Stage Command Processing #YG4

I’ve tried everything but unable to find a solution went through the code examples still not able to make it work please someone can help that will be great…

Here are my logs:

[tester::#YG4] [handshake] master: Sent bytes: "$88\r\nREDIS0011\xfa\tredis-ver\x057.2.0\xfa\nredis-bits\xc0@\xfa\x05ctime\xc2m\b\xbce\xfa\bused-mem°\xc4\x10\x00\xfa\baof-base\xc0\x00\xff\xf0n;\xfe\xc0\xffZ\xa2"
[tester::#YG4] [handshake] Sent RDB file.
[tester::#YG4] [propagation] master: > SET foo 123
[tester::#YG4] [propagation] master: Sent bytes: "*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\n123\r\n"
[your_program] Starting Handle Connection on localhost 6379
[tester::#YG4] [propagation] master: > SET bar 456
[tester::#YG4] [propagation] master: Sent bytes: "*3\r\n$3\r\nSET\r\n$3\r\nbar\r\n$3\r\n456\r\n"
[tester::#YG4] [propagation] master: > SET baz 789
[tester::#YG4] [propagation] master: Sent bytes: "*3\r\n$3\r\nSET\r\n$3\r\nbaz\r\n$3\r\n789\r\n"
[tester::#YG4] [test] Getting key foo
[tester::#YG4] [test] client: $ redis-cli GET foo
[tester::#YG4] [test] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[tester::#YG4] [test] client: Received bytes: "$-1\r\n"
[tester::#YG4] [test] client: Received RESP null bulk string: "$-1\r\n"
[tester::#YG4] [test] Retrying... (1/5 attempts)
[tester::#YG4] [test] client: > GET foo
[tester::#YG4] [test] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[your_program] Processing GET operation with following args [{Value:foo IsNull:false}]
[tester::#YG4] [test] client: Received bytes: "$-1\r\n"
[tester::#YG4] [test] client: Received RESP null bulk string: "$-1\r\n"
[your_program] Processing GET operation with following args [{Value:foo IsNull:false}]
[tester::#YG4] [test] Retrying... (2/5 attempts)
[tester::#YG4] [test] client: > GET foo
[tester::#YG4] [test] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[tester::#YG4] [test] client: Received bytes: "$-1\r\n"
[tester::#YG4] [test] client: Received RESP null bulk string: "$-1\r\n"
[your_program] Processing GET operation with following args [{Value:foo IsNull:false}]
[tester::#YG4] [test] Retrying... (3/5 attempts)
[tester::#YG4] [test] client: > GET foo
[tester::#YG4] [test] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[tester::#YG4] [test] client: Received bytes: "$-1\r\n"
[tester::#YG4] [test] client: Received RESP null bulk string: "$-1\r\n"
[tester::#YG4] [test] Retrying... (4/5 attempts)
[tester::#YG4] [test] client: > GET foo
[tester::#YG4] [test] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[your_program] Processing GET operation with following args [{Value:foo IsNull:false}]
[tester::#YG4] [test] client: Received bytes: "$-1\r\n"
[tester::#YG4] [test] client: Received RESP null bulk string: "$-1\r\n"
[your_program] Processing GET operation with following args [{Value:foo IsNull:false}]
[tester::#YG4] [test] Retrying... (5/5 attempts)
[tester::#YG4] [test] client: > GET foo
[tester::#YG4] [test] client: Sent bytes: "*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n"
[tester::#YG4] [test] client: Received bytes: "$-1\r\n"
[tester::#YG4] [test] client: Received RESP null bulk string: "$-1\r\n"
[your_program] Processing GET operation with following args [{Value:foo IsNull:false}]
[tester::#YG4] Expected simple string or bulk string, got NIL
[tester::#YG4] Test failed
[tester::#YG4] Terminating program
[tester::#YG4] Program terminated successfully

And here’s a snippet of my code:

func SetCommand(args tools.Array) (string, error) {
	_, expiryTime := "", time.Time{}
	var err error
	var message string
	fmt.Println("Here For SET")
	if len(args) != 2 && len(args) != 4 {
		fmt.Println("\n Failed at length \n", len(args))
		err = fmt.Errorf("Incorrect Input :: %v", args)
		return message, err
	}
	key, okKey := args[0].(tools.BulkString)
	value, okValue := args[1].(tools.BulkString)

	if !okKey || !okValue {
		fmt.Println("\n Failed at Key Val \n", len(args))
		err = fmt.Errorf("Incorrect Input :: %v", args[0])
		return message, err
	}
	now :=
		time.Now()
	SetStoreMux.Lock()
	if len(args) == 4 {
		typeEx, okTypeEx := args[2].(tools.BulkString)
		exVal, okExVal := args[3].(tools.BulkString)
		if !okTypeEx || !okExVal {
			fmt.Println("\n Failed at Time \n", len(args))
			err = fmt.Errorf("Incorrect Input :: %v %v", args[2], args[3])
			return message, err
		}
		timeToExpire, convertErr := strconv.Atoi(exVal.Value)
		if convertErr != nil {
			err = fmt.Errorf("Incorrect Convert Time %v %v", args[2], args[3])
			return message, err
		}
		var typeTime string = strings.ToUpper(typeEx.Value)
		switch typeTime {
		case "PX":
			{
				expiryTime = now.Add(time.Millisecond * time.Duration(timeToExpire))
			}
		case "EX":
			{
				expiryTime = now.Add(time.Second * time.Duration(timeToExpire))
			}
		}
	}

	SetStore[key.Value] = &DataStore{
		value:    value.Value,
		expiry:   expiryTime,
		createOn: now,
	}
	SetStoreMux.Unlock()

	message = tools.SimpleString("OK").Encode()
	replicaConn := tools.GetReplicaConns()
	if len(replicaConn) > 0 {
		for _, conn := range replicaConn {
			fmt.Println("Conn Details For Slave", conn)
			serverhelpers.SendSetCommandToReplica(conn, key.Value, value.Value)
		}
	}
	return message, err
}

type ServerConfig struct {
	port     int64
	hostName string
	id       string
	role     string
	replicas []net.Conn
}

@skadoodle1201 the logs suggest that the propagated command wasn’t actually processed. Could you try adding debug logs around the areas where the propagated commands are supposed to be received? That could help narrow this down.

More on this here: How do I debug test failures? - CodeCrafters

Hey @rohitpaulk ,

I tired multiple things and i am able to go through the testcase but one of the old one is failing(#HC6), Here’s whats happening i have a goroutine to connect with the master my code is not moving beyond that point its not even calling the function. I am going to push my code to the github please help me resolve it.

func spwanServer(port int, role string, replicaOf string) {
	serve, err := net.Listen("tcp", tools.MasterHostGetter()+":"+strconv.Itoa(port))
	if err != nil {
		fmt.Println("Failed to bind to port ", port)
		os.Exit(1)
	}
	tools.InitServerConfig(int64(port), tools.MasterHostGetter(), role)

	if role == tools.SLAVE_ROLE {
		masterConn := masterConn(replicaOf)
		serverhelpers.SendHandshakePing(masterConn)
               //not able to go after this line below and it does not even print inside handleConnection and exits the testcases.
		go handleConnection(masterConn, tools.MASTER_ROLE)
                fmt.Println("This Does Not Get Printed")
	}

	for {
		fmt.Println("Waiting for new connection")
		conn, err := serve.Accept()

		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		go handleConnection(conn, role)
	}
}

func handleConnection(conn net.Conn, role string) {
	for {
		fmt.Println("Waiting for new command")
		var buf = make([]byte, 128)
		count, err := conn.Read(buf)
		if err != nil {
			if err == io.EOF {
				return
			}
			fmt.Println("Error reading: ", err.Error())
		}
		// Print the received message
		readBuf := buf[:count]
		parsedData, data, err := tools.Parse(readBuf)
		if err != nil {
			fmt.Println("Error parsing: ", err.Error())
			continue
		}

		if len(data) != 0 && strings.Contains(string(data), "+FULLRESYNC") || strings.Contains(string(data), "+OK") {
			continue
		}
		if len(data) != 0 {
			p, d, _ := tools.Parse(data)
			fmt.Println("data: ", string(data))
			if len(d) != 0 {
				fmt.Println("not all data are processed, data left: ", string(d))
				continue
			}
			a, ok := p.(tools.Array)
			if !ok {
				fmt.Println("parsed command data should be array")
				continue
			}
			operation, ok := a[0].(tools.BulkString)
			if !ok {
				fmt.Println("operation item should be string: ", a[0])
				continue
			}
			args := tools.Array{}
			if len(a) > 1 {
				args = a[1:]
			}
			fmt.Printf("Processing %s operation with following args %+v", operation.Value, args)

			resMessage := commands.RedisCommands(operation.Value, args, role)
			_, err = conn.Write([]byte(resMessage))

			if err != nil {
				fmt.Printf("Error writing: %v", err.Error())
				continue
			}
		}
		arr, ok := parsedData.(tools.Array)
		if !ok {
			fmt.Println("parsed command data should be array")
			continue
		}
		operation, ok := arr[0].(tools.BulkString)
		if !ok {
			fmt.Println("operation item should be string: ", arr[0])
			continue
		}
		if operation.Value == "PSYNC" {
			tools.AppendNewReplicaConn(conn)
			fmt.Println("PSYNC received")
			dataToSend := "+FULLRESYNC " + tools.ServerUUID() + " 0\r\n"
			_, err := conn.Write([]byte(dataToSend))
			if err != nil {
				fmt.Println("Error writing:", err.Error())
			}
			rdbHex := "524544495330303131fa0972656469732d76657205372e322e30fa0a72656469732d62697473c040fa056374696d65c26d08bc65fa08757365642d6d656dc2b0c41000fa08616f662d62617365c000fff06e3bfec0ff5aa2"
			rdbBytes, _ := hex.DecodeString(rdbHex)

			dataToSend = "$" + strconv.Itoa(len(rdbBytes)) + "\r\n" + string(rdbBytes)
			_, rdbFileErr := conn.Write([]byte(dataToSend))
			if rdbFileErr != nil {
				fmt.Printf("Error writing: %v", rdbFileErr.Error())
				continue
			}
			continue
		}
		args := tools.Array{}
		if len(arr) > 1 {
			args = arr[1:]
		}
		fmt.Printf("Processing %s operation with following args %+v", operation.Value, args)

		resMessage := commands.RedisCommands(operation.Value, args, role)
		_, err = conn.Write([]byte(resMessage))

		if err != nil {
			fmt.Printf("Error writing: %v", err.Error())
			continue
		}
	}

}

Here are the logs for reference :

[tester::#EH4] Running tests for Stage #EH4 (Replication - Send handshake (2/3))
[tester::#EH4] Master is running on port 6379
[tester::#EH4] $ ./spawn_redis_server.sh --port 6380 --replicaof "localhost 6379"
[tester::#EH4] master: Waiting for replica to initiate handshake with "PING" command
[tester::#EH4] Received ["ping"]
[your_program] Logs from your program will appear here!
[your_program] Master connection failed Already running on port  6379
[your_program] Server starting role:  localhost 6379
[tester::#EH4] master: Sent "PONG"
[tester::#EH4] master: Waiting for replica to send "REPLCONF listening-port 6380" command
[tester::#EH4] Received ["REPLCONF", "listening-port", "6380"]
[tester::#EH4] master: Sent "OK"
[tester::#EH4] master: Waiting for replica to send "REPLCONF capa" command
[tester::#EH4] Received ["REPLCONF", "capa", "psync2"]
[tester::#EH4] master: Sent "OK"
[tester::#EH4] Test passed.

[tester::#GL7] Running tests for Stage #GL7 (Replication - Send handshake (1/3))
[tester::#GL7] Master is running on port 6379.
[tester::#GL7] $ ./spawn_redis_server.sh --port 6380 --replicaof "localhost 6379"
[tester::#GL7] master: Waiting for replica to initiate handshake with "PING" command
[tester::#GL7] Received ["ping"]
[your_program] Logs from your program will appear here!
[your_program] Master connection failed Already running on port  6379
[your_program] Server starting role:  localhost 6379
[tester::#GL7] master: Sent "PONG"
[tester::#GL7] Test passed.

[tester::#XC1] Running tests for Stage #XC1 (Replication - Initial Replication ID and Offset)
[tester::#XC1] $ ./spawn_redis_server.sh
[your_program] Logs from your program will appear here!
[your_program] Waiting for new connection
[tester::#XC1] client: $ redis-cli INFO replication
[tester::#XC1] Received "# Replication\nrole:master\nconnected_slaves:0\nmaster_replid:bf43b902d3ca59a8e0c7518a07ae3d2a310548c8\nmaster_repl_offset:0\nsecond_repl_offset:-1\nrepl_backlog_active:0\nrepl_backlog_size:1048576\nrepl_backlog_first_byte_offset:0\nrepl_backlog_histlen:"
[tester::#XC1] Found master_replid:xxx in response.
[tester::#XC1] Found master_reploffset:0 in response.
[tester::#XC1] Test passed.
[your_program] Waiting for new connection
[your_program] Waiting for new command
[your_program] dataType:  *2
[your_program] $4
[your_program] INFO
[your_program] $11
[your_program] replication
[your_program]
[your_program] dataType:  $4
[your_program] INFO
[your_program] $11
[your_program] replication
[your_program]
[your_program] data: IN BULK STRING INFO
[your_program] $11
[your_program] replication
[your_program]
[your_program] dataType:  $11
[your_program] replication
[your_program]
[your_program] data: IN BULK STRING replication
[your_program]
[your_program] Processing INFO operation with following args [{Value:replication IsNull:false}]INFO [{replication false}]
[your_program] master
[your_program] Waiting for new command

[tester::#HC6] Running tests for Stage #HC6 (Replication - The INFO command on a replica)
[tester::#HC6] Master is running on port 6379
[tester::#HC6] $ ./spawn_redis_server.sh --port 6380 --replicaof "localhost 6379"
[your_program] Logs from your program will appear here!
[your_program] Master connection failed Already running on port  6379
[your_program] Server starting role:  localhost 6379
[tester::#HC6] client: $ redis-cli INFO replication
[tester::#HC6] Received: "" (no content received)
[tester::#HC6]            ^ error
[tester::#HC6] Error: Expected start of a new RESP2 value (either +, -, :, $ or *)
[tester::#HC6] Test failed (try setting 'debug: true' in your codecrafters.yml to see more details)

github repo link : GitHub - skadoodle1201/o7-is

Thanks for help.

@skadoodle1201 Just checking, do you still need any assistance on #HC6?

Hey andy1li,

Yes i would really appreciate your help.

@skadoodle1201 When I comment out this line, your code can pass #HC6.

Suggestions:

  1. Investigate whether masterConn was set up properly.
  2. Add logs inside serverhelpers.SendHandshakePing and debug what’s causing the code to hang.

Closing this thread due to inactivity. If you still need assistance, feel free to reopen or start a new discussion!

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.