# Snapshots

Los servidores de contenido compilarán periódicamente resúmenes de las entidades activas que están hospedando, llamados *snapshots*. Son [archivos](https://github.com/decentraland/docs/blob/main/contributor/filesystem.md) regulares y se pueden descargar usando su identificador.

Los snapshots se crean con base diaria, semanal, mensual y anual. Cada uno contiene el conjunto de entidades activas que cambiaron desde el snapshot anterior para ese rango.

Los snapshots contendrán versiones en conflicto de las mismas entidades (es decir, diferentes [manifest files](https://github.com/decentraland/docs/blob/main/contributor/entities.md#properties) asociados al mismo pointer) a medida que se actualizan. Al escanearlos, los clientes deben conservar la versión del snapshot más reciente. Dado que los servidores de contenido pueden eliminar archivos inactivos, no se garantiza que las versiones obsoletas de entidades estén disponibles para su descarga.

Cuando un nuevo snapshot *reemplaza* a los anteriores (por ejemplo, un snapshot semanal que combina una serie de diarios), sus metadatos indican qué archivos previos son reemplazados para que los clientes no necesiten descargarlos.

El conjunto completo de entidades activas puede descubrirse combinando todos los snapshots disponibles (más detalles abajo), conservando la entidad más reciente referenciada por cada [pointer](https://github.com/decentraland/docs/blob/main/contributor/pointers.md) descubierto en el proceso.

Puedes experimentar con snapshots usando código funcional en la [practice](https://github.com/decentraland/docs/blob/main/contributor/practice.md) sección.

### Descubriendo Snapshots <a href="#discover" id="discover"></a>

Para ubicar el conjunto actual de snapshots, usa el [`snapshots` endpoint](https://decentraland.github.io/catalyst-api-specs/#tag/Content-Server/operation/getSnapshots). La respuesta contiene un arreglo de elementos con estos campos:

| Campo                     | Valor                                                                                  |
| ------------------------- | -------------------------------------------------------------------------------------- |
| `generationTimestamp`     | La marca de tiempo Unix UTC cuando se creó este snapshot.                              |
| `hash`                    | El [file](https://github.com/decentraland/docs/blob/main/contributor/filesystem.md).   |
| `numberOfEntities`        | El número de entradas en el archivo snapshot.                                          |
| `replacedSnapshotHashes`  | Un arreglo con los `hash` de cualquier snapshot reemplazado por este.                  |
| `timeRange.initTimestamp` | La marca de tiempo Unix UTC (en milisegundos) para el comienzo del rango del snapshot. |
| `timerange.endTimestamp`  | La marca de tiempo Unix UTC (en milisegundos) para el final del rango del snapshot.    |

Por ejemplo:

```json
{
  "generationTimestamp": 1684979298844,
  "hash": "bafybeiflmm46nr4vv2h3wuzbx3pukcz7ju4fhbfzt6yxmoo533uktlgru4",
  "numberOfEntities": 12345,
  "replacedSnapshotHashes": [ "bafybeicw6x75ieaxfwynekbyhpcsgctpjkt6cb4j6oa7s57qjj6e4b5phd" ],
  "timeRange": {
     "initTimestamp": 1684281600000,
     "endTimestamp": 1684886400000
  }
}
```

### Descargando Snapshots <a href="#download" id="download"></a>

Usando el `hash` campo de un snapshot, los clientes pueden descargar el archivo asociado que contiene las entidades creadas o actualizadas en ese rango de tiempo.

Los archivos snapshot comienzan con esta línea exacta:

```
### Decentraland json snapshot
```

Después de eso, cada línea es un documento JSON que describe una [entity](https://github.com/decentraland/docs/blob/main/contributor/entities.md) con los siguientes campos:

| Campo             | Valor                                                                                                                                              |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `entityId`        | El identificador inmutable para esta [entity](https://github.com/decentraland/docs/blob/main/contributor/entities.md).                             |
| `entityType`      | Uno de `escena`, `perfil`, `wearable`, `emote`, `store` o `outfits`.                                                                               |
| `pointers`        | Un arreglo de [pointers](https://github.com/decentraland/docs/blob/main/contributor/pointers.md) que resuelven (o solían resolver) a esta entidad. |
| `entityTimestamp` | La marca de tiempo Unix UTC (en milisegundos) cuando esta entidad fue subida.                                                                      |
| `authChain`       | El [auth chain](https://github.com/decentraland/docs/blob/main/contributor/entities.md#ownership) para esta entidad.                               |

Una entrada típica se ve así:

```json
{
  "entityId": "bafkreigrvaqynmiglpvewwhn2yd63q5dvagrrt5jbhimzvbrn5kimj5zne",
  "entityType": "wearable",
  "pointers": ["urn:decentraland:matic:collections-v2:0x11a6879861f36cbad632a4e7226816a16139fb33:0"],
  "entityTimestamp": 1671117456129,
  "authChain": [
    // ... authentication chain payloads and signatures
  ]
}
```

{% hint style="info" %}
Si tienes la intención de parsear un snapshot línea por línea, recuerda saltarte (o mejor aún, validar) la primera con el encabezado, y estar listo para manejar una línea vacía al final del archivo.
{% endhint %}

#### Iniciando un Índice de Entidades <a href="#index-start" id="index-start"></a>

Los clientes que quieran indexar el conjunto completo de entidades activas deben procesar todos los snapshots actualmente disponibles y mantener la más reciente [entity](https://github.com/decentraland/docs/blob/main/contributor/entities.md) para cada [pointer](https://github.com/decentraland/docs/blob/main/contributor/pointers.md).

La estrategia más simple es procesar los snapshots en orden cronológico inverso (es decir, del más reciente al más antiguo), ignorando pointers que ya hayan sido descubiertos, para conservar la referencia a la última entidad.

En pseudocódigo:

```py
# Descargar el conjunto actual de snapshots, y ordenarlos de más nuevo a más viejo:
snapshots = get_snapshots()
snapshots.sort('timeRange.initTimestamp', DESCENDING)

seen_pointers = set()

# Procesar snapshots, conservando la entidad más nueva para cada pointer:
for snapshot in snapshots:
    items = get_snapshot_items(snapshot) 

    for item in items:
        if any(pointer in seen_pointers for pointer in item.pointers):
            discard(item)
        else:
            keep(item)
            seen_pointers.update(item.pointers)
```

Dado que entidades individuales pueden ser referenciadas por múltiples pointers (como es común en [escenas](https://docs.decentraland.org/contributor/contributor-es/contenido/tipos-de-entity/scenes)), todos ellos deben ser verificados antes de decidir conservar o descartar el elemento.

{% hint style="info" %}
Los archivos snapshot para los rangos de tiempo más largos pueden ser muy grandes. Para propósitos de desarrollo y experimentación que no requieren indexar el conjunto completo de entidades, se recomienda usar los snapshots más pequeños. El conjunto resultante de entidades será incompleto pero válido.
{% endhint %}

#### Actualizando un Índice de Entidades <a href="#index-update" id="index-update"></a>

Los clientes que mantienen un índice de entidades actualizado pueden hacer llamadas periódicas al [`snapshots`](https://decentraland.github.io/catalyst-api-specs/#tag/Content-Server/operation/getSnapshots) endpoint, y determinar si descargar cada archivo considerando:

* ¿Fue el snapshot identificado por `hash` ya descargado?
* ¿Está `hash` en la `replacedSnapshotHashes` lista de otro snapshot que ya fue descargado?
* ¿Es el `timeRange` relevante para los propósitos actuales?

Si se deben procesar nuevos snapshots, se puede usar la misma estrategia que arriba para actualizar un dataset existente.

### Ejemplos

En la [practice](https://github.com/decentraland/docs/blob/main/contributor/practice.md) sección, encontrarás ejemplos de código que funcionan con el sistema de snapshots.
