/* * check_replica_sizes -- (internal) check if all replicas are large * enough to hold data from a healthy replica */ static int check_replica_sizes(struct pool_set *set, struct poolset_health_status *set_hs) { LOG(3, "set %p, set_hs %p", set, set_hs); ssize_t pool_size = -1; for (unsigned r = 0; r < set->nreplicas; ++r) { /* skip broken replicas */ if (!replica_is_replica_healthy(r, set_hs)) continue; /* get the size of a pool in the replica */ ssize_t replica_pool_size; if (REP(set, r)->remote) /* XXX: no way to get the size of a remote pool yet */ replica_pool_size = (ssize_t)set->poolsize; else replica_pool_size = replica_get_pool_size(set, r); if (replica_pool_size < 0) { LOG(1, "getting pool size from replica %u failed", r); set_hs->replica[r]->flags |= IS_BROKEN; continue; } /* check if the pool is bigger than minimum size */ enum pool_type type = pool_hdr_get_type(HDR(REP(set, r), 0)); if ((size_t)replica_pool_size < pool_get_min_size(type)) { LOG(1, "pool size from replica %u is smaller than the minimum size allowed for the pool", r); set_hs->replica[r]->flags |= IS_BROKEN; continue; } /* check if each replica is big enough to hold the pool data */ if (set->poolsize < (size_t)replica_pool_size) { ERR( "some replicas are too small to hold synchronized data"); return -1; } if (pool_size < 0) { pool_size = replica_pool_size; continue; } /* check if pools in all healthy replicas are of equal size */ if (pool_size != replica_pool_size) { ERR("pool sizes from different replicas differ"); return -1; } } return 0; }
/* * check_replica_sizes -- (internal) check if all replicas are large * enough to hold data from a healthy replica */ static int check_replica_sizes(struct pool_set *set, struct poolset_health_status *set_hs) { LOG(3, "set %p, set_hs %p", set, set_hs); unsigned healthy_replica = replica_find_healthy_replica(set_hs); if (set->poolsize < replica_get_pool_size(set, healthy_replica)) { ERR("some replicas are too small to hold synchronized data"); return -1; } return 0; }
/* * validate_args -- (internal) check whether passed arguments are valid */ static int validate_args(struct pool_set *set_in, struct pool_set *set_out) { LOG(3, "set_in %p, set_out %p", set_in, set_out); if (set_in->directory_based) { ERR("transform of directory poolsets is not supported"); errno = EINVAL; return -1; } /* * check if all parts in the target poolset are large enough * (now replication works only for pmemobj pools) */ if (replica_check_part_sizes(set_out, PMEMOBJ_MIN_POOL)) { ERR("part sizes check failed"); return -1; } /* * check if all directories for part files exist and if part files * do not reoccur in the poolset */ if (check_paths(set_out)) return -1; /* * check if set_out has enough size, i.e. if the target poolset * structure has enough capacity to accommodate the effective size of * the source poolset */ ssize_t master_pool_size = replica_get_pool_size(set_in, 0); if (master_pool_size < 0) { ERR("getting pool size from master replica failed"); return -1; } if (set_out->poolsize < (size_t)master_pool_size) { ERR("target poolset is too small"); errno = EINVAL; return -1; } return 0; }
/* * copy_data_to_broken_parts -- (internal) copy data to all parts created * in place of the broken ones */ static int copy_data_to_broken_parts(struct pool_set *set, unsigned healthy_replica, unsigned flags, struct poolset_health_status *set_hs) { size_t poolsize = replica_get_pool_size(set, healthy_replica); for (unsigned r = 0; r < set_hs->nreplicas; ++r) { /* skip unbroken and consistent replicas */ if (replica_is_replica_healthy(r, set_hs)) continue; struct pool_replica *rep = REP(set, r); struct pool_replica *rep_h = REP(set, healthy_replica); for (unsigned p = 0; p < rep->nparts; ++p) { /* skip unbroken parts from consistent replicas */ if (!replica_is_part_broken(r, p, set_hs) && replica_is_replica_consistent(r, set_hs)) continue; const struct pool_set_part *part = &rep->part[p]; size_t off = replica_get_part_data_offset(set, r, p); size_t len = replica_get_part_data_len(set, r, p); /* do not allow copying too much data */ if (off >= poolsize) continue; if (off + len > poolsize) len = poolsize - off; void *src_addr = ADDR_SUM(rep_h->part[0].addr, off); /* First part of replica is mapped with header */ size_t fpoff = (p == 0) ? POOL_HDR_SIZE : 0; /* copy all data */ if (!is_dry_run(flags)) { memcpy(ADDR_SUM(part->addr, fpoff), src_addr, len); pmem_msync(ADDR_SUM(part->addr, fpoff), len); } } } return 0; }
/* * copy_replica_data_bw -- (internal) copy data between replicas of two * poolsets, starting from the end of the pool */ static void copy_replica_data_bw(struct pool_set *set_dst, struct pool_set *set_src, unsigned repn) { LOG(3, "set_in %p, set_out %p, repn %u", set_src, set_dst, repn); ssize_t pool_size = replica_get_pool_size(set_src, repn); if (pool_size < 0) { LOG(1, "getting pool size from replica %u failed", repn); pool_size = (ssize_t)set_src->poolsize; } size_t len = (size_t)pool_size - POOL_HDR_SIZE - replica_get_part_data_len(set_src, repn, 0); size_t count = len / POOL_HDR_SIZE; void *src = ADDR_SUM(PART(REP(set_src, repn), 1)->addr, len); void *dst = ADDR_SUM(PART(REP(set_dst, repn), 1)->addr, len); while (count-- > 0) { src = ADDR_SUM(src, -(ssize_t)POOL_HDR_SIZE); dst = ADDR_SUM(dst, -(ssize_t)POOL_HDR_SIZE); pmem_memcpy_persist(dst, src, POOL_HDR_SIZE); } }