ballerina

How to make functions accessing a table thread safe?


I have the following code, and I want to make sure that the actions on the table are thread-safe (and make the accessor functions isolated). How should I go about it?

final table<Patient> key(id) patientTable = table [
    {id: "a0384c7b-d22b-4627-9a2d-dfce02987c96", firstName: "John", lastName: "Doe", dob: {year: 1954, month: 10, day: 23}, gender: "male"},
    {id: "722d6531-a9f3-4eb7-8735-aa7151f9bb39", firstName: "Jane", lastName: "Doe", dob: {year: 1972, month: 9, day: 17}, gender: "female"}
];

service / on EP {
    isolated resource function post patients(@http:Payload PatientEntry patientEntry) returns Patient {
        Patient patient = {id: uuid:createRandomUuid(), ...patientEntry};
        patientTable.put(patient);
        return patient;
    }

    isolated resource function get patients/[string patientId]() returns Patient|http:NotFound {
        if !patientTable.hasKey(patientId) {
            return {body: "Patient not found"};
        }
        return patientTable.get(patientId);
    }
}

I can't make the patientTable readonly, since I need to edit the table from the resource functions. Also tried having locks in all places where I access the patientTable, I still get invalid access of mutable storage in an 'isolated' function(BCE3943)


Solution

  • import ballerina/uuid;
    import ballerina/http;
    
    type Patient record {readonly string id;};
    type PatientEntry record {||};
    
    final isolated table<Patient> key(id) patientTable = table [
        {id: "a0384c7b-d22b-4627-9a2d-dfce02987c96", firstName: "John", lastName: "Doe", dob: {year: 1954, month: 10, day: 23}, gender: "male"},
        {id: "722d6531-a9f3-4eb7-8735-aa7151f9bb39", firstName: "Jane", lastName: "Doe", dob: {year: 1972, month: 9, day: 17}, gender: "female"}
    ];
    
    isolated service / on new http:Listener(8080) {
        isolated resource function post patients(@http:Payload PatientEntry patientEntry) returns Patient {
            Patient patient = {id: uuid:createRandomUuid(), ...patientEntry};
            lock {
                patientTable.put(patient.clone());
            }
            return patient;
        }
    
        isolated resource function get patients/[string patientId]() returns Patient|http:NotFound {
            lock {
                if !patientTable.hasKey(patientId) {
                    return {body: "Patient not found"};
                }
                return patientTable.get(patientId).clone();
            }
        }
    }