Skip to content

Commit 592ba11

Browse files
author
jose.castillo
committed
fix: possible memory leaks
1 parent 93e665e commit 592ba11

File tree

2 files changed

+36
-18
lines changed

2 files changed

+36
-18
lines changed

group.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,13 @@ func (g *group) Set(ctx context.Context, key string, value []byte, expire time.T
207207
// Se usa la copia del valor para crear la ByteView.
208208
bv := transport.ByteViewWithExpire(valueCopy, expire) // <-- Usa valueCopy
209209

210-
// Usamos el lock del loadGroup (singleflight de Get) para sincronizar
211-
// el acceso a las cachés locales (mainCache y hotCache).
212-
// Esto previene condiciones de carrera si un Get local ocurre
213-
// exactamente al mismo tiempo que esta actualización.
214210
g.loadGroup.Lock(func() {
215-
g.mainCache.Add(key, bv) // Añade/sobrescribe en mainCache.
216-
g.hotCache.Remove(key) // Elimina de hotCache (si existía).
211+
if g.isOwner(key) {
212+
g.mainCache.Add(key, bv)
213+
g.hotCache.Remove(key)
214+
} else {
215+
g.hotCache.Add(key, bv)
216+
}
217217
})
218218

219219
// Actualizar todos los demás peers en el clúster (excepto este nodo y el dueño).

transport/http_transport.go

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -368,43 +368,61 @@ type HttpClient struct {
368368
client *http.Client
369369
}
370370

371+
// Get recupera la clave <in.Group>/<in.Key> desde el peer remoto y
372+
// coloca el resultado en 'out'. Se asegura de que el buffer que
373+
// viene del sync.Pool NO quede referenciado por la caché.
371374
func (h *HttpClient) Get(ctx context.Context, in *pb.GetRequest, out *pb.GetResponse) error {
375+
// ---------- 1. lanzar la petición --------------------------
372376
var res http.Response
373377
if err := h.makeRequest(ctx, http.MethodGet, in, nil, &res); err != nil {
374378
return err
375379
}
376380
defer res.Body.Close()
381+
382+
// ---------- 2. gestionar códigos de error ------------------
377383
if res.StatusCode != http.StatusOK {
378-
// Limit reading the error body to max 1 MiB
384+
// leemos (máx. 1 MiB) el cuerpo de error para incluirlo en el msg
379385
msg, _ := io.ReadAll(io.LimitReader(res.Body, 1024*1024))
380386

381-
if res.StatusCode == http.StatusNotFound {
387+
switch res.StatusCode {
388+
case http.StatusNotFound:
382389
return &ErrNotFound{Msg: strings.Trim(string(msg), "\n")}
383-
}
384-
385-
if res.StatusCode == http.StatusServiceUnavailable {
390+
case http.StatusServiceUnavailable:
386391
return &ErrRemoteCall{Msg: strings.Trim(string(msg), "\n")}
392+
default:
393+
return fmt.Errorf("server returned: %v, %v", res.Status, string(msg))
387394
}
388-
389-
return fmt.Errorf("server returned: %v, %v", res.Status, string(msg))
390395
}
391396

397+
// ---------- 3. leer la respuesta en un *bytes.Buffer -------
392398
b := bufferPool.Get().(*bytes.Buffer)
393399
b.Reset()
394400
defer func() {
401+
// devolvemos el buffer al pool SOLO si no es gigante
395402
if b.Cap() <= maxBufferSize {
396-
bufferPool.Put(b) // único Put
403+
bufferPool.Put(b)
397404
}
398405
}()
399406

400-
_, err := io.Copy(b, res.Body)
401-
if err != nil {
407+
if _, err := io.Copy(b, res.Body); err != nil {
402408
return fmt.Errorf("reading response body: %v", err)
403409
}
404-
err = proto.Unmarshal(b.Bytes(), out)
405-
if err != nil {
410+
411+
// ---------- 4. des-serializar el proto ---------------------
412+
if err := proto.Unmarshal(b.Bytes(), out); err != nil {
406413
return fmt.Errorf("decoding response body: %v", err)
407414
}
415+
416+
// ---------- 5. copia defensiva para romper la referencia ---
417+
// out.Value apunta al array interno de 'b'. Copiamos para
418+
// que la caché no retenga ese array y el buffer pueda
419+
// reutilizarse / ser liberado por el GC.
420+
if out.Value != nil {
421+
val := make([]byte, len(out.Value))
422+
copy(val, out.Value)
423+
out.Value = val
424+
}
425+
408426
return nil
409427
}
410428

0 commit comments

Comments
 (0)