# Buggy code
def default_size_estimator(ctx, chunk, multiplier=1):
    exec_size = int(sum(ctx[inp.key][0] for inp in chunk.inputs or ()) * multiplier)

    total_out_size = 0
    chunk_sizes = dict()
    outputs = chunk.op.outputs
    for out in outputs:
        try:
            chunk_size = out.nbytes if not out.is_sparse() else exec_size
            if np.isnan(chunk_size):
                raise TypeError
            chunk_sizes[out.key] = chunk_size
            total_out_size += chunk_size
        except (AttributeError, TypeError, ValueError):
            pass
    exec_size = max(exec_size, total_out_size)
    for out in outputs:
        if out.key in chunk_sizes:
            store_size = chunk_sizes[out.key]
        else:
            store_size = max(
                exec_size // len(outputs), total_out_size // max(len(chunk_sizes), 1)
            )
        try:
            max_sparse_size = (
                out.nbytes + np.dtype(np.int64).itemsize * np.prod(out.shape) * out.ndim
            )
        except TypeError:  # pragma: no cover
            max_sparse_size = np.nan
        if not np.isnan(max_sparse_size):
            store_size = min(store_size, max_sparse_size)
        ctx[out.key] = (store_size, exec_size // len(outputs))


# Traceback (mars.error)
In [1]: from mars.deploy.local import new_cluster

In [2]: cluster = new_cluster(scheduler_n_process=2, worker_n_process=3, shared_memory='20M',)

In [3]: import mars.tensor as mt

In [4]: import scipy.sparse as sps

In [5]: a = sps.csr_matrix((10000, 10000))

In [6]: b = sps.csr_matrix((10000, 1))

In [7]: t1 = mt.tensor(a)

In [8]: t2 = mt.tensor(b)


In [9]: from mars.session import new_session

In [10]: cluster.session.run(t1 * t2)

Unexpected exception occurred in ChunkHolderActor.spill_size.
Traceback (most recent call last):
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/utils.py", line 298, in _wrapped
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/worker/chunkholder.py", line 123, in spill_size
raise SpillExhausted
mars.errors.SpillExhausted
Unhandled exception in promise call
Traceback (most recent call last):
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/promise.py", line 304, in _wrapped
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/utils.py", line 298, in _wrapped
return func(*args, **kwargs)
File "/Users/hekaisheng/Documents/mars_dev/mars/mars/worker/chunkholder.py", line 123, in spill_size
raise SpillExhausted
mars.errors.SpillExhausted
....

# Fixed code
def default_size_estimator(ctx, chunk, multiplier=1):
    exec_size = int(sum(ctx[inp.key][0] for inp in chunk.inputs or ()) * multiplier)

    total_out_size = 0
    chunk_sizes = dict()
    outputs = chunk.op.outputs
    for out in outputs:
        try:
            chunk_size = out.nbytes if not out.is_sparse() else exec_size
            if np.isnan(chunk_size):
                raise TypeError
            chunk_sizes[out.key] = chunk_size
            total_out_size += chunk_size
        except (AttributeError, TypeError, ValueError):
            pass
    exec_size = max(exec_size, total_out_size)
    for out in outputs:
        if out.key in ctx:
            continue
        if out.key in chunk_sizes:
            store_size = chunk_sizes[out.key]
        else:
            store_size = max(
                exec_size // len(outputs), total_out_size // max(len(chunk_sizes), 1)
            )
        try:
            max_sparse_size = (
                out.nbytes + np.dtype(np.int64).itemsize * np.prod(out.shape) * out.ndim
            )
        except TypeError:  # pragma: no cover
            max_sparse_size = np.nan
        if not np.isnan(max_sparse_size):
            store_size = min(store_size, max_sparse_size)
        ctx[out.key] = (store_size, exec_size // len(outputs))