什么是限制mnesia中某个键下的记录数量的惯用方法?

时间:2011-11-10 03:09:43

标签: erlang limit mnesia

我使用mnesia为用户存储数据,记录是一个像

这样的包

{username,field1,filed2,timestamp}

为了不让数据库爆炸,我想设置属于某个用户的记录数限制,比如说,如果用户的记录数达到500,那么具有最旧时间戳的记录是在插入新记录之前删除。

有一种有效的方法吗?

提前致谢。

2 个答案:

答案 0 :(得分:0)

我提供了两种可能性。一个适合您的设计,一个引入您的记录定义的小变化。看看哪一个最适合您的需求。下面的第一个是在你的设计中工作。

-record(user,{username,field1,field2,timestamp}).

%% execute the function below in a mnesia transaction

insert(#user{username = U,timestamp = _T} = User)->
    case mnesia:read({user,U}) of
        [] -> mnesia:write(User);
        AllHere -> 
            case length(AllHere) == 500 of
                false -> %% not yet 500
                      mnesia:write(User);
                true -> 
                    %% value has reached 500
                    %% get all timestamps and get the 
                    %% oldest record and delete it
                    %% 
                    OldRecord = get_oldest_stamp(AllHere),
                    ok = mnesia:delete_object(Record),
                    mnesia:write(User)
            end
    end.

get_oldest_stamp(UserRecords)-> 
    %% here you do your sorting
    %% and return the record with
    %% oldest timestamp
    ....
    OldRecord.


交易中的length/1功能不是最佳的。让我们想一个更好的方法。另外,我不知道你的时间戳是怎样的,所以你确定你有办法对它们进行排序并查找最新的时间戳,挑出拥有这个时间戳的记录然后将其返回。我已经给出了这个解决方案,以适应您的设计。我也认为我们需要一些indexing。下一个实现对我来说似乎更好。如果我们可以更改记录定义并引入一个oldest字段bool(),我们将其编入索引

-record(user,{
            username,
            field1,
            field2,
            timestamp,
            oldest      %% bool(), indexed
}).
insert_user(Username,Field1,Field2)-> User = #user{ username = Username, field1 = Field1, field2 = Field2, timestamp = {date(),time()}
}. insert(User).
%% execute this within a mnesia transaction
insert(#user{username = U} = User)-> case mnesia:read({user,U}) of [] -> mnesia:write(User#user{oldest = true}); AllHere -> case length(AllHere) == 500 of false -> %% unset all existing records' oldest field %% to false F = fun(UserX)-> ok = mnesia:delete_object(UserX), ok = mnesia:write(UserX#user{oldest = false}) end, [F(XX) || XX <- AllHere], ok = mnesia:write(User#user{oldest = true}); true -> [OldestRec] = mnesia:index_read(user,true,oldest), ok = mnesia:delete_object(OldestRec), ok = mnesia:write(User#user{oldest = true}) end end.
以上实现对我来说似乎更好。成功!!

答案 1 :(得分:0)

另一种方法可能是让你的记录

{username, value_list, timestamp} 

其中value_list包含值列表。你的桌子现在可以是一套而不是一个包,你可以做这种事情

{NewList,_ignore}=lists:Split(500, [{NewFld1,NewFld2}|Value_list]),
%mnesia:write(Rec#{value_list=NewList}) type of code goes next

无论何时插入。 NewList将包含最多500个元素,并且由于最旧的元素在最后,如果您有501个元素,则最后一个将位于_ignore列表中,您将...忽略。

您在密钥上进行常规时间查询以进行某些列表操作,但根据您的应用程序可能是一个很好的权衡。您也可以摆脱时间戳字段和相关代码来维护该字段。