Repository: apache/dubbo
File: dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java (Java)

Code before:
     */
    public synchronized String calAndGetRevision() {
        if (revision != null && !updated) {
            return revision;
        }

        updated = false;

        if (CollectionUtils.isEmptyMap(services)) {
            this.revision = EMPTY_REVISION;
        } else {
            String tempRevision = calRevision();
            if (!StringUtils.isEquals(this.revision, tempRevision)) {
                if (logger.isInfoEnabled()) {
                    logger.info(String.format(
                            "metadata revision changed: %s -> %s, app: %s, services: %d",
                            this.revision, tempRevision, this.app, this.services.size()));
                }
                this.revision = tempRevision;
                this.rawMetadataInfo = JsonUtils.toJson(this);
            }
        }
        return revision;
    }

    public String calRevision() {
        StringBuilder sb = new StringBuilder();
        sb.append(app);
        for (Map.Entry<String, ServiceInfo> entry : new TreeMap<>(services).entrySet()) {
            sb.append(entry.getValue().toDescString());
        }
        return RevisionResolver.calRevision(sb.toString());
    }

    public void setRevision(String revision) {
        this.revision = revision;
    }

    @Transient
    public String getContent() {
        return this.rawMetadataInfo;
    }

    public String getApp() {
        return app;
    }

    public void setApp(String app) {
        this.app = app;
    }


Review comment (suggestion):
It would be better to add a lock here to prevent concurrent modification.

BTW, please check other operation will aquire lock

Code after:
     */
    public synchronized String calAndGetRevision() {
        if (revision != null && !updated) {
            return revision;
        }

        updated = false;

        if (CollectionUtils.isEmptyMap(services)) {
            this.revision = EMPTY_REVISION;
        } else {
            String tempRevision = calRevision();
            if (!StringUtils.isEquals(this.revision, tempRevision)) {
                if (logger.isInfoEnabled()) {
                    logger.info(String.format(
                            "metadata revision changed: %s -> %s, app: %s, services: %d",
                            this.revision, tempRevision, this.app, this.services.size()));
                }
                this.revision = tempRevision;
                this.rawMetadataInfo = JsonUtils.toJson(this);
            }
        }
        return revision;
    }

    public synchronized String calRevision() {
        StringBuilder sb = new StringBuilder();
        sb.append(app);
        for (Map.Entry<String, ServiceInfo> entry : new TreeMap<>(services).entrySet()) {
            sb.append(entry.getValue().toDescString());
        }
        return RevisionResolver.calRevision(sb.toString());
    }

    public void setRevision(String revision) {
        this.revision = revision;
    }

    @Transient
    public String getContent() {
        return this.rawMetadataInfo;
    }

    public String getApp() {
        return app;
    }

    public void setApp(String app) {
        this.app = app;
    }