2011-08-15 30 views
9

Vì tôi đang viết một ứng dụng máy chủ Minecraft đơn giản trong Erlang, giờ đây tôi quan tâm đến câu hỏi về cách lưu trữ và sửa đổi dữ liệu chunk hiệu quả. Đối với những người không biết về nội bộ của Minecraft: Tôi cần lưu trữ nhiều tệp nhị phân (100-1000) có kích thước tối đa 32kB trong bộ nhớ. Cho đến thời điểm này các tệp nhị phân dựng sẵn của Erlang là đủ. Nhưng máy chủ phải đọc và thay đổi một số byte (theo id của chúng) trong các tệp nhị phân này khá thường xuyên và tôi không muốn sao chép chúng xung quanh mọi lúc.
Một tính năng rất hay để có là nhập và xuất từ ​​/ sang các tệp nhị phân chuẩn của Erlang.Mảng byte có thể thay đổi lớn trong Erlang

Có bất kỳ phần mở rộng hoặc cơ sở dữ liệu Erlang hoặc bất kỳ thứ gì tôi có thể sử dụng cho điều này không?

+0

Cuối cùng, sự cố đã được giải quyết bằng cách sử dụng các tệp nhị phân có kích thước 4kB và chỉnh sửa chúng cho mỗi thay đổi khối. Trong khi đây không phải là từ cuối cùng về hiệu quả cập nhật, nhưng nó tiết kiệm bộ nhớ. Trong trường hợp bạn muốn có một cái nhìn, mã có sẵn tại [Github] (https://github.com/clonejo/mc-erl). – clonejo

Trả lời

9

Kể từ mã nhị phân được read-only, tôi có thể nghĩ ra những phương pháp sau đây (giả sử bạn mong đợi tốc độ cao thay đổi):

  1. Sử dụng cấu trúc cây giống với những chương trình không thay đổi tương đối nhỏ trong lá. Trong trường hợp đó, khi bạn sửa đổi dữ liệu, bạn chỉ cần tạo lại nhị phân lá nhỏ + tất cả các nút đến gốc. Giả sử rằng những thay đổi là "cục bộ" đối với một số vị trí, tôi nghĩ, bạn có thể bắt đầu với octo-tree.
  2. Sử dụng tệp nhị phân "lớn" + danh sách thay đổi (có thể là danh sách hàm đơn giản). Khi bạn cần sửa đổi thế giới, chỉ cần thêm chức năng mới vào danh sách. Khi ai đó yêu cầu trạng thái thế giới, lấy nhị phân cơ sở và áp dụng tất cả các thay đổi từ danh sách. Theo thời gian "squash" tất cả các thay đổi và chuẩn bị một nhị phân trạng thái cơ sở mới. Điều này có thể được kết hợp với cách tiếp cận trước đó (cây có cặp nhị phân/thay đổi trong lá).
  3. Di chuyển quản lý thế giới có thể thay đổi sang mã bên ngoài. Bạn có thể sử dụng NIFs hoặc Ports. Tôi nghĩ, đó sẽ là cách nhanh nhất. Ngoài ra, tôi nghĩ rằng nó sẽ tương đối dễ dàng để thực hiện nó. Phiên bản API đầu tiên có thể đơn giản như world:new(X, Y, Z) -> ref(); world:get(Ref, X, Y, Z); world:set(Ref, X, Y, Z, Value);
+0

Cảm ơn câu trả lời tuyệt vời của bạn! Tôi cho rằng tôi sẽ sử dụng cách thứ hai, vì những thay đổi không thường xuyên (không quá 5 byte mỗi giây và trình phát). – clonejo

0

1000 32kb nhị phân không phải là vấn đề lớn. bạn nói thay đổi một số byte? có lẽ sẽ tốt hơn nếu bạn chỉ tạo một bản ghi các phần khác nhau mà nhị phân có thể chứa hoặc thường được sửa đổi, theo cách đó bạn có thể sửa đổi các phần của nhị phân mà không cần sao chép các phần khác. Với ets bạn không phải lo lắng về một loạt các bản sao nhị phân chờ đợi để được gc'ed. Nó vẫn tạo một bản sao và nó vẫn được gc'ed nhưng không giống như một quá trình. Bạn cũng có thể sử dụng tùy chọn fullsweep_after để thực hiện quá trình dọn dẹp thường xuyên hơn.

3

Đề xuất của tôi là sử dụng cấu trúc "dây". Về cơ bản một cấu trúc giống cây, thường là một cây splay hoặc ngón tay mà bạn chỉ cho phép thay đổi các phần của cây. Làm điều này đúng cách cho phép bạn có những điều tốt nhất của cả hai thế giới: bất biến cùng với các cập nhật nhanh.

Tôi không biết thực hiện dây, nhưng đây là những gì bạn muốn làm.

Cách khác là sử dụng mẫu làm mảng có thể thay đổi. Nó là khá nhanh cho loại điều đó.

Tùy chọn thứ ba là sử dụng cấu trúc cây không gian để đại diện cho thế giới của bạn. Octrees hoặc cấu trúc giống như BSP là thứ tôi muốn lấy, một cách mù quáng.

Các vấn đề liên quan