<commit_before>// Copyright 2012 <NAME>. All Rights Reserved.
// Author: <EMAIL> (<NAME>)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package backup

import ()

// A stateful object that knows how to keep track of files that are hard-linked
// together. This is an implementation detail; you should not touch it.
type LinkResolver interface {
	// Register the supplied path, which points to the given inode on the given
	// containing device. Return a path that has already been registered here, if
	// any.
	Register(containingDevice int32, inode uint64, path string) *string
}

// Create an empty link resolver. This is an implementation detail; you should
// not touch it.
func NewLinkResolver() LinkResolver {
	return &linkResolver{make(map[mapElement]string)}
}

type mapElement struct {
	containingDevice int32
	inode            uint64
}

type linkResolver struct {
	alreadySeen map[mapElement]string
}

func (r *linkResolver) Register(containingDevice int32, inode uint64, path string) *string {
	elem := mapElement{containingDevice, inode}

	// Have we already seen this element?
	if prevPath, ok := r.alreadySeen[elem]; ok {
		return &prevPath
	}

	// This is the first time. Insert it.
	r.alreadySeen[elem] = path

	return nil
}
<commit_msg>Made link resolver thread-safe.<commit_after>// Copyright 2012 <NAME>. All Rights Reserved.
// Author: <EMAIL> (<NAME>)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package backup

import (
	"sync"
)

// A stateful object that knows how to keep track of files that are hard-linked
// together. This is an implementation detail; you should not touch it.
type LinkResolver interface {
	// Register the supplied path, which points to the given inode on the given
	// containing device. Return a path that has already been registered here, if
	// any.
	//
	// This method may be called multiple times concurrently.
	Register(containingDevice int32, inode uint64, path string) *string
}

// Create an empty link resolver. This is an implementation detail; you should
// not touch it.
func NewLinkResolver() LinkResolver {
	return &linkResolver{alreadySeen: make(map[mapElement]string)}
}

type mapElement struct {
	containingDevice int32
	inode            uint64
}

type linkResolver struct {
	mutex sync.Mutex
	alreadySeen map[mapElement]string  // Protected by mutex
}

func (r *linkResolver) Register(containingDevice int32, inode uint64, path string) *string {
	elem := mapElement{containingDevice, inode}

	r.mutex.Lock()
	defer r.mutex.Unlock()

	// Have we already seen this element?
	if prevPath, ok := r.alreadySeen[elem]; ok {
		return &prevPath
	}

	// This is the first time. Insert it.
	r.alreadySeen[elem] = path

	return nil
}

{'fraction_non_alphanumeric': 0.08797417271993543, 'fraction_numerical': 0.010761366693570083, 'mean_word_length': 3.6944444444444446, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4403975', 'n_tokens_mistral': 1048, 'n_tokens_neox': 997, 'n_words': 463}