You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							94 lines
						
					
					
						
							2.3 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							94 lines
						
					
					
						
							2.3 KiB
						
					
					
				| package operation | |
| 
 | |
| import ( | |
| 	"context" | |
| 	"fmt" | |
| 	"io" | |
| 
 | |
| 	"github.com/seaweedfs/seaweedfs/weed/pb" | |
| 
 | |
| 	"google.golang.org/grpc" | |
| 
 | |
| 	"github.com/seaweedfs/seaweedfs/weed/pb/volume_server_pb" | |
| 	"github.com/seaweedfs/seaweedfs/weed/storage/needle" | |
| ) | |
| 
 | |
| func TailVolume(masterFn GetMasterFn, grpcDialOption grpc.DialOption, vid needle.VolumeId, sinceNs uint64, timeoutSeconds int, fn func(n *needle.Needle) error) error { | |
| 	// find volume location, replication, ttl info | |
| 	lookup, err := LookupVolumeId(masterFn, grpcDialOption, vid.String()) | |
| 	if err != nil { | |
| 		return fmt.Errorf("look up volume %d: %v", vid, err) | |
| 	} | |
| 	if len(lookup.Locations) == 0 { | |
| 		return fmt.Errorf("unable to locate volume %d", vid) | |
| 	} | |
| 
 | |
| 	volumeServer := lookup.Locations[0].ServerAddress() | |
| 
 | |
| 	return TailVolumeFromSource(volumeServer, grpcDialOption, vid, sinceNs, timeoutSeconds, fn) | |
| } | |
| 
 | |
| func TailVolumeFromSource(volumeServer pb.ServerAddress, grpcDialOption grpc.DialOption, vid needle.VolumeId, sinceNs uint64, idleTimeoutSeconds int, fn func(n *needle.Needle) error) error { | |
| 	return WithVolumeServerClient(true, volumeServer, grpcDialOption, func(client volume_server_pb.VolumeServerClient) error { | |
| 		ctx, cancel := context.WithCancel(context.Background()) | |
| 		defer cancel() | |
| 
 | |
| 		stream, err := client.VolumeTailSender(ctx, &volume_server_pb.VolumeTailSenderRequest{ | |
| 			VolumeId:           uint32(vid), | |
| 			SinceNs:            sinceNs, | |
| 			IdleTimeoutSeconds: uint32(idleTimeoutSeconds), | |
| 		}) | |
| 		if err != nil { | |
| 			return err | |
| 		} | |
| 
 | |
| 		for { | |
| 			resp, recvErr := stream.Recv() | |
| 			if recvErr != nil { | |
| 				if recvErr == io.EOF { | |
| 					break | |
| 				} else { | |
| 					return recvErr | |
| 				} | |
| 			} | |
| 
 | |
| 			needleHeader := resp.NeedleHeader | |
| 			needleBody := resp.NeedleBody | |
| 			version := needle.Version(resp.Version) | |
| 			if version == 0 { | |
| 				version = needle.GetCurrentVersion() | |
| 			} | |
| 
 | |
| 			if len(needleHeader) == 0 { | |
| 				continue | |
| 			} | |
| 
 | |
| 			for !resp.IsLastChunk { | |
| 				resp, recvErr = stream.Recv() | |
| 				if recvErr != nil { | |
| 					if recvErr == io.EOF { | |
| 						break | |
| 					} else { | |
| 						return recvErr | |
| 					} | |
| 				} | |
| 				needleBody = append(needleBody, resp.NeedleBody...) | |
| 			} | |
| 
 | |
| 			n := new(needle.Needle) | |
| 			n.ParseNeedleHeader(needleHeader) | |
| 			err = n.ReadNeedleBodyBytes(needleBody, version) | |
| 			if err != nil { | |
| 				return err | |
| 			} | |
| 
 | |
| 			err = fn(n) | |
| 
 | |
| 			if err != nil { | |
| 				return err | |
| 			} | |
| 
 | |
| 		} | |
| 		return nil | |
| 	}) | |
| }
 |